Compare commits

...

89 Commits

Author SHA1 Message Date
4fc06a449c Merge pull request '13.0.30 - Le pansement d'Illysis' (#795) from feature/v13-corrections into v13
All checks were successful
Release Creation / build (release) Successful in 1m27s
Reviewed-on: https, #795
2026-02-18 00:43:46 +01:00
929d6af173 Saisie de valeurs négatives 2026-02-17 00:36:08 +01:00
e15ed9d05d Jet de compétence avec défauts
Utilisation de carac par défaut et difficulté par défaut à l'ouverture
de la fenêtre de jet depuis une compétence
2026-02-16 23:58:45 +01:00
3699bc19b8 Fix: soins d'un joueur à l'autre
Les données dans rollData ne pouvaient pas être serialisées
2026-02-06 13:42:27 +01:00
15510b99d8 Merge pull request 'feature/v13-corrections' (#794) from feature/v13-corrections into v13
All checks were successful
Release Creation / build (release) Successful in 2m45s
Reviewed-on: https, #794
2026-01-19 21:44:59 +01:00
fa30705989 Affichage de l'XP des sorts et caractéristiques 2026-01-17 03:45:42 +01:00
04f550dd21 Fix jet de résistance V2
sans cométence s'il n'y a pas de sélection
2026-01-16 08:47:51 +01:00
850cae3979 Attaques V2 depuis onglet combat 2026-01-16 08:47:50 +01:00
7b514d5159 Background arme inutilisable 2026-01-14 23:55:03 +01:00
d78ede4f59 Fix missing import 2026-01-14 23:47:01 +01:00
3de00fd001 Merge pull request 'Correction chat appel moral' (#793) from feature/v13-corrections into v13
All checks were successful
Release Creation / build (release) Successful in 2m28s
Reviewed-on: https, #793
2026-01-13 22:08:14 +01:00
1b340e526c Simplifications en cherchant bug rêve actuel
Parfois, le rêve actuel est ajouté dans les caractéristiques des
feuilles de personnage.

Simplifications pour essayer d'isoler le souci.
2026-01-10 23:07:25 +01:00
3f3bf293b1 Correction Fenêtre astrologie v13 2026-01-10 22:28:39 +01:00
80b4cde130 Status effect v13 2026-01-10 22:28:09 +01:00
74fecac47e Correction chat appel moral 2026-01-09 02:06:16 +01:00
f1ee8fb45b Merge pull request 'Fix: attaques à distance' (#792) from feature/v13-corrections into v13
Reviewed-on: https, #792
2026-01-07 14:44:21 +01:00
52a5084419 Fix: attaques à distance 2026-01-05 19:12:55 +01:00
8fdf49bfce Message d'information affiché une seule fois toutes les 24 heures
All checks were successful
Release Creation / build (release) Successful in 10m20s
2025-12-30 10:30:14 +01:00
f897a94e60 Merge pull request '## 13.0.27 - Les lunettes d'Illysis' (#791) from feature/v13-corrections into v13
Reviewed-on: https, #791
2025-12-30 10:19:45 +01:00
e6aed2d554 Amélioration des choix d'attaque 2025-12-30 01:30:19 +01:00
0dd671d8a5 Mise à jour d'images
- ajout d'un coffre
- ajout de tissu soie
- correction d'image pour utiliser le style classique
2025-12-30 01:30:15 +01:00
a5c4303012 Les conteneurs ouverts sont mis à jour 2025-12-30 01:29:31 +01:00
ad84e36d43 Suppression timestamp doublon 2025-12-30 01:25:29 +01:00
af9ecda30f fix changelog 2025-12-30 01:25:29 +01:00
7b1374dd2c Merge pull request 'Correction caracs créature' (#790) from feature/v13-corrections into v13
All checks were successful
Release Creation / build (release) Successful in 2m40s
Reviewed-on: https, #790
2025-12-21 21:38:56 +01:00
3b4ed13247 Caracs créature 2025-12-21 12:00:20 +01:00
ecb653c40c Fix link !
All checks were successful
Release Creation / build (release) Successful in 1m37s
2025-12-20 18:43:08 +01:00
03051218b6 Info message !
All checks were successful
Release Creation / build (release) Successful in 3m21s
2025-12-20 17:44:11 +01:00
88a1e35648 Info message ! 2025-12-20 17:42:47 +01:00
0525acde53 Merge pull request 'v13.0.24 - Le grand oubli d'Illysis' (#789) from feature/v13-corrections into v13
Reviewed-on: https, #789
2025-12-20 17:20:59 +01:00
bf2b7567ca Correction cuisiner
- icone de l'action différente de "manger"
- correction tooltip dans fenêtre de jet
- support d'images svg pour les item-actions
- prise en compte de la difficulté de préparation brute
2025-12-19 23:52:12 +01:00
c305f9712c Correction boutons de maladresses pour joueur 2025-12-19 03:02:35 +01:00
10085dc3f1 Correction enchantement 2025-12-19 02:00:08 +01:00
bd39c0f633 Correction message d'erreur sur Hook update/create
Les Hook d'update/create sont appelés pour tous les joueurs.
Le filtrage pour n'exécuter qu'une fois les modifications
supplémentaires se basait sur game.user.activeGM qui est
toujours défini, au lieu de le comparer au joueur courant
pour s'assurer de ne faire l'action que pour le premier
joueur connecté propriétaire du personnage.
2025-12-19 01:52:18 +01:00
a52d10a3b3 Bouton pour supprimer les anciens messages 2025-12-18 19:44:00 +01:00
9fd6d9026a Merge pull request 'feature/v13-corrections' (#788) from feature/v13-corrections into v13
All checks were successful
Release Creation / build (release) Successful in 3m0s
Reviewed-on: https, #788
2025-12-15 22:20:25 +01:00
9d1a1238a2 Suivi du rollMode pour les jets 2025-12-15 21:27:45 +01:00
0563286cca Correction de combat
- filtrage des parades selon l'attaque
- gestion des tactiques
2025-12-15 01:09:35 +01:00
dbe5d0b974 Correction: jet avec compétence 2025-12-15 01:09:35 +01:00
80cac2fadb Recherche des caractéristiques de créature
La recherche des caractéristiques de créatures cherche aussi
dans les caractéristiques de leurs compétences
2025-12-15 01:09:34 +01:00
d591c5c183 Statut inconscient pour les créatures 2025-12-15 01:09:34 +01:00
df9f8a9f5f Suppression de l'option "mode test roll V2"
Ce mode permettait de ne pas fermer la fenêtre de jet pour des tests
répétitifs, ce n'est plus nécessaire
2025-12-15 01:09:34 +01:00
67a085f884 Corrections soins des blessures V2 2025-12-15 01:09:34 +01:00
e33727ac8d Consommation part le consommateur
Pour afficher la fenêtre d'appréciation côté acheteur, et utiliser ses
dés
2025-12-15 01:09:34 +01:00
455beb2820 Merge pull request '13.0.22 - Les reflets d'Illysis' (#787) from feature/v13-corrections into v13
All checks were successful
Release Creation / build (release) Successful in 2m29s
Reviewed-on: https, #787
2025-12-13 18:17:15 +01:00
c4794cd276 La fenêtre d'appréciation doit se fermer
la fenêtre d'appréciation se ferme automatiquement
2025-12-13 02:54:24 +01:00
f6581c7b3b Changement de message de non appréciation
Quand l'appréciation ne donne pas de jet de moral, le message
donnant les raisons est ajouté dans le tchat
2025-12-13 02:45:07 +01:00
c61cc5da18 Amélioration des remoteActorCall 2025-12-13 02:43:58 +01:00
bb51d1c1d0 Correction erreur sur appel chance
cas particulier non reproduit, le savedRoll ne peut pas être dupliqué.
2025-12-13 02:31:42 +01:00
a5165a2909 Pas de tactiques pour les attaques à distance 2025-12-13 02:08:34 +01:00
75a50257ac Attaques à distance sans tokens
- correction d'attaques à distance depuis l'onglet combat sans token
sélectionné
2025-12-13 02:07:49 +01:00
31764e0118 Fermeture de la fenêtre de jet depuis un lien 2025-12-13 02:05:46 +01:00
2894905fc6 Fenêtre de jet V2 pour jet quelconque 2025-12-13 02:04:27 +01:00
d6a492eef2 Fix: aucune oeuvre connu
La fenêtre de jet se comporte correctement si le personnage
ne connait pas d'oeuvre
2025-12-13 01:09:00 +01:00
97cb730ab5 Fix: aucun jeu connu
La fenêtre de jet se comporte correctement si le personnage
ne sait pas jouer,
2025-12-13 01:09:00 +01:00
a4e614860a Fix: aucune méditation connue
Cas de haut-rêvant ne connaissant pas de méditations
2025-12-13 01:09:00 +01:00
8077656ea1 Fix erreurs dans console sur fenêtre TMR
ajout de mécanismes de sécurité pour éviter erreur rare (liée
à un état étrange après avoir été dans les TMR)
2025-12-13 01:09:00 +01:00
7ea1f36852 Corrections mise sort en réserve
La mise en réserve de sorts depuis la feuille de personne
ne marchait pas à cause de rêve variables
2025-12-13 01:08:59 +01:00
2c7fd32ae6 Fix typo 2025-12-13 01:08:59 +01:00
9574792963 Icones pour acteurs et scènes 2025-12-13 01:08:59 +01:00
2912b5ce9b Fix possession - defense 2025-12-13 01:08:59 +01:00
b939d9bebf Correction affichage colonnes réussite
affichage des colonnes de réussite/ajustement nécessaire
2025-12-13 01:08:59 +01:00
6907344be7 Résolution de soucis inter-types de jets V2
- diminution de la dépendance au token cible pour les attaques
- ne pas proposer l'attaque sur les jets "par défaut"
- filtrer les sous-parties inutiles (ie: sorts pour les attaques, etc)
2025-12-12 17:42:43 +01:00
3567885030 Police lisible dans les messages de tchat
Résout des problèmes de polices pas toujours cohérentes dans
les messages de tchat
2025-12-12 17:40:27 +01:00
15ce2588b8 Correction sur défense 2025-12-11 03:26:38 +01:00
30090872d4 Gestion défense à distance 2025-12-11 03:12:49 +01:00
4f4e00b298 Ajout: Information de distance 2025-12-11 03:12:49 +01:00
697247e931 Fix: protection sur actions sans acteur/propriété
Cas rencontré une fois, un jet de chance d'un autre
joueur, pouvait être tenté.

Cas plus étrange, un jet de chance alors que le jet sauvegardé
n'avait pas d'actorId
2025-12-11 03:12:48 +01:00
894161c0bf Fix: Encombrement décimal 2025-12-11 03:12:48 +01:00
6882b4819c Correction: ajout de notes 2025-12-11 03:12:48 +01:00
275c144ea2 Préparation v13.0.22 2025-12-11 03:12:48 +01:00
3c5cfbb609 Merge pull request 'v13.0.21 - La folie d'Illysis' (#786) from feature/v13-possession-v2 into v13
All checks were successful
Release Creation / build (release) Successful in 3m21s
Reviewed-on: https, #786
2025-12-08 20:23:57 +01:00
36c771518d v13.0.21 2025-12-08 20:12:17 +01:00
dd7a3700dc Appréciation des services 2025-12-08 20:10:56 +01:00
f0736015a7 Surcharge de couleurs de style
Les titres dans les descriptions n'étaient pas bien affichés dans la
fenêtre de jet
2025-12-08 19:40:21 +01:00
aae603d798 Appréciation de plats 2025-12-08 19:39:21 +01:00
d9bc6309fb Correction des bonus des Cyans 2025-12-08 01:42:57 +01:00
c14361919c Update compendiums 2025-12-08 01:42:55 +01:00
b26c39cf21 Ajout des options d'appréciation
L'appréciation utilise:

- un niveau de qualité (qui réutilise la qualité sur les items en ayant)
- un bon moment (coeur/musique/...)
- un niveau de jet de moral
- une caractéristique (perception)
- une compétence

Les bon moments passés sont remis à zéro lors du passage de
château dormant.

Ajout des jets de moral très heureux.

Ajout de jet d'appréciation sur les résultats des oeuvres et des jeux.
2025-12-08 01:42:47 +01:00
ca2d17bd25 Encombrement avec décimales 2025-12-07 23:48:41 +01:00
a243209c90 Fix: selection parmi les cibles 2025-12-07 02:52:19 +01:00
90435c07b4 cleanup unused imports 2025-12-06 21:12:30 +01:00
46d09c7bd9 Dimension des zones editeur
amélioration des zones de saisie des éditeurs (journaux, ...)
2025-12-06 21:12:30 +01:00
05036877ed Possessions dans HUD
Permettre de commencer les possessions V2
2025-12-06 21:12:25 +01:00
98e8c7a10c Gestion de possession - fin de round
- affichage du message pour indiquer l'état d'une possession en fin de
round
- bouton de conjuration depuis la feuille de personnage
2025-12-05 20:12:14 +01:00
19cabe816e Gestion défense et compteur de possession 2025-12-05 20:12:14 +01:00
706aa657b1 Méthode rollPossession pour attaque possession
- Ajout d'une méthode pour ouvrir le dialogue en mode possession
- gestion des information de possession
- fenêtre défense possession
- préparation des messages de tchat
2025-12-05 20:12:09 +01:00
fd3f988a4f Roll V2 mode possession 2025-11-28 19:44:06 +01:00
981282d809 Ajout de méthode getConjurations
Pour lister les compétences de possession/conjuration de manière
homogène (tout actor doué de rêve)
2025-11-28 00:04:16 +01:00
1314 changed files with 41589 additions and 11880 deletions

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><defs><radialGradient id="skoll-open-chest-gradient-2"><stop offset="0%" stop-color="#b8e986" stop-opacity="1"></stop><stop offset="100%" stop-color="#ffe0af" stop-opacity="1"></stop></radialGradient><linearGradient x1="0" x2="0" y1="0" y2="1" id="skoll-open-chest-gradient-5"><stop offset="0%" stop-color="#417505" stop-opacity="1"></stop><stop offset="100%" stop-color="#8b572a" stop-opacity="1"></stop></linearGradient></defs><g class="" transform="translate(1,0)" style=""><path d="M457.03 213.037 416.514 100.24C425 77.232 433.27 68.075 437.527 64.633c3.162-2.563 5.922-3.534 8.185-2.904 4.134 1.168 8.775 7.7 12.278 17.456 11.266 31.347 10.377 87.094-.96 133.85zm-324.287-17.9 312.804 34.84-43.82-122.1L145.558 79.34c2.593 36.102-1.913 79.913-12.817 115.796zM128.98 77.5l-45.06-5.02 37.03 103.123c7.773-32.06 10.625-68.357 8.03-98.102zm-27.52-50.31c-3.793 3.1-10.77 10.666-18.25 28.566L402.23 91.3c5.333-13.695 11.37-24.702 17.88-32.495L108.796 24.13c-2.573-.29-5.415 1.51-7.338 3.06zm280.63 283.338.61 169.352 66.352-53.63-.61-169.35zM366.163 487.9 46.62 452.306 46 278.396l319.553 35.594zM216.726 337.648a9.777 9.777 0 0 0 5.168-9.405c-.248-6.367-5.364-12.092-11.43-12.857h-.125c-6.14-.693-10.904 3.927-10.646 10.335a13.973 13.973 0 0 0 5.767 10.543l-2.17 25.073 17.57 2.005zm219.28-91.983-307.46-34.25v59.54l242.712 27.037zM58.31 263.13l54.34 6.058v-49.98z" fill="#fff" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><polygon points="256,512,0,256,256,0,512,256" fill="#000" fill-opacity="1"></polygon><g class="" transform="translate(8,-12)" style=""><path d="M282.83 18.877c21.567 6.146 36.328 15.205 40.572 28.77a71.007 71.007 0 0 0-4.066 2.363c-25.655 5.807-53.084 18.634-81.047 34.363 20.225-4.69 36.705-4.42 47.544 3.324-5.712 10.3-10.797 22.294-15.123 36.06-21.343 67.922-125.678-80.577-189.065-5.255C41.47 166.24 92.702 212.342 26.5 294.29c35.583-4.14 45.11-9.47 62.416-36.21 10.44-16.13 28.52-22.1 44.668-21.45-12.718 11.206-25.786 30.354-38.21 59.895 19.832-18.528 44.927-38.68 71.603-40.005.912 6.354-2.408 13.74-12.008 21.418C93.21 327.327 15.58 364.185 19.83 476.504c5.558-11.267 11.646-20.31 17.574-28.617 5.98 29.582 28.2 53.8 92.99 40.482-46.928-6.407-76.268-59.586-45.355-82.528 62.716-46.544 128.82 1.436 269.9-75.342a79.832 79.832 0 0 1 7.164-3.46c-2.246 19.6-12.367 39.84-22.362 57.14 14.26-10.38 25.415-20.147 33.928-29.262 2.14 26.14-11.748 54.65-25.393 78.268 43.26-31.49 61.19-57.976 63.207-78.422 9.334 36.678-1.895 95.547-25.03 123.492 77.553-39.433 106.608-77.127 109.76-190.664 1.662-59.824-66.23-60.536-56.435-101.344 11.945-49.756 6.768-84.69-7.565-107.947-19.6-49.73-79.99-59.74-149.385-59.423zM89.8 47.684C54.69 47.534 45.233 83.056 55.724 117c17.146-51.504 70.414-44.24 111.17-34.367-33.282-25.005-58.707-34.87-77.096-34.95zm254.595 30.742c18.643 21.37 29.373 43.02 10.105 65.732-26.562-16.677-26.985-39.252-10.105-65.732zm74.494 48.6c3.655-.013 7.78.35 12.473 1.09-1.706 30.506-14.4 33-46.634 32.154 8.335-22.146 14.416-33.176 34.16-33.245zm-84.677 40.316c9.652.1 20.258 2.84 30.598 8.918 44.65 26.246 21.934 73.314-4.1 74.78-15.174.855 1.443-23.842-16.17-38.476-15.258-12.678-38.596 12.53-45.204-5.78-8.218-22.693 10.21-39.696 34.877-39.442zm60.18 246.168c-24.195 27.825-58.89 60.1-99.444 31.41 16.625 45.643 68.87 70.465 99.443-31.41z" fill="#fff" fill-opacity="1" transform="translate(102.4, 102.4) scale(0.6, 0.6) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -1,449 +1 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512.07 512" style="enable-background:new 0 0 512.07 512;" xml:space="preserve">
<style type="text/css">
.st0{display:none;}
.st1{display:inline;}
.st2{fill:#DCDCDC;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<g id="icon_x5F_sidebar_x5F_chat" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M180,480.93c14-15.25,27.95-29.3,40.56-44.47c14.18-17.05,23.54-36.69,26.34-59.05
c1.66-13.29-0.67-25.98-5.04-38.48c-1.8-5.15-5.7-5.52-10.23-5.78c-18.92-1.08-37.99-1.21-56.71-3.83
c-40-5.59-76.63-19.99-107.18-47.16c-36.18-32.19-46.99-77.73-26.93-122.29c15.37-34.14,40.96-59.17,71.93-78.94
c47.68-30.44,100.22-45.65,156.55-49.23c41.61-2.64,81.81,2.91,120.81,17.42c26.15,9.73,48.71,24.87,66.74,46.2
c29.1,34.42,32.23,80.62,8.86,120.58c-23.61,40.37-58.93,67.06-100.58,86.28c-10.17,4.7-20.81,8.38-31.3,12.36
c-4.3,1.63-6.47,4.24-6.8,9.02c-2.04,29.43-14.23,54.78-32.77,77.05c-29.18,35.06-66,59.86-107.6,77.9
C184.67,479.39,182.56,480.01,180,480.93z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_rolltable" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M255.1,55.46c6.7,2.37,12.64,3.53,17.63,6.38c47.83,27.36,95.49,55,143.19,82.58
c1.76,1.02,3.5,2.14,5.06,3.43c4.67,3.85,4.73,8.08-0.19,11.57c-4.48,3.18-9.3,5.9-14.07,8.66
c-43.81,25.34-87.68,50.58-131.43,76.01c-12.79,7.43-25.19,8.02-38.18,0.44c-47.26-27.53-94.66-54.81-141.95-82.29
c-11.67-6.78-11.5-10.86,0.17-17.61c45.93-26.57,91.78-53.27,137.82-79.64C240.07,61.03,247.84,58.57,255.1,55.46z
M256.6,177.07c8.18-2.74,15.83-4.76,23.02-7.85c6.75-2.9,11.12-8.42,11.32-16.12c0.2-7.86-4.55-13.18-10.98-16.36
c-16.34-8.07-32.92-8.99-48.94,0.93c-13.18,8.17-13.33,23.46,0.28,30.9C238.94,172.75,248.01,174.3,256.6,177.07z
M139.44,174.49c10.51,0.36,20.31-1.78,28.43-8.85c7.92-6.9,8.07-17.96,0.6-25.36c-13.09-12.97-44.39-13.07-57.62-0.19
c-8.94,8.7-8.15,19.73,2.02,27.08C120.8,172.91,129.82,174.83,139.44,174.49z M371.05,174.5c13.13,0.01,20.45-1.93,27.72-7.04
c11.22-7.88,11.04-21.8-0.38-29.44c-14.58-9.76-37.05-9.78-51.54-0.06c-11.6,7.78-11.75,21.98-0.23,29.88
C354.29,173.1,362.88,175.12,371.05,174.5z M257.2,200.1c-10.74-0.21-20.43,1.8-28.51,8.53c-9.63,8.02-9.2,19.91,0.7,27.6
c13.81,10.71,40.59,10.4,54.05-0.63c9.82-8.05,9.29-21.21-1.19-28.54C274.59,201.7,265.94,199.86,257.2,200.1z M255.77,105.95
c10.86-0.08,20.49-2.25,28.35-9.28c8.51-7.61,8.52-17.75,0.3-25.54c-13.52-12.81-43.78-12.59-57.1,0.4
c-7.45,7.27-7.44,17.61,0.19,24.78C235.62,103.93,245.78,105.61,255.77,105.95z"/>
</g>
<g>
<path class="st2" d="M73.56,270.29c-0.01-23.47-0.01-46.95,0-70.42c0-2.24-0.04-4.5,0.09-6.73c0.55-9.08,4.45-11.43,12.3-7.03
c14.77,8.29,29.43,16.78,44.1,25.25c31.29,18.06,62.49,36.27,93.87,54.16c13.59,7.75,19.9,19.03,19.84,34.61
c-0.18,47.56-0.07,95.12-0.07,142.68c0,1.02,0,2.04-0.03,3.06c-0.37,10.88-4.46,13.26-13.91,7.81
c-46.51-26.8-93.02-53.6-139.43-80.56c-11.08-6.44-16.76-16.38-16.77-29.35C73.56,319.28,73.57,294.79,73.56,270.29z
M238.89,301.12c-1.04-15.22-9.94-29.1-25.87-37.67c-12.78-6.88-25.53,0.97-25.17,15.07c0.45,18,8.76,32.2,24.15,41.47
C226.27,328.58,238.87,320.93,238.89,301.12z M238.88,424.25c-0.03-14.84-11.77-33.85-24.91-40.35
c-13.82-6.83-27.24,1.36-26.24,16.4c1.14,17.22,9.44,30.68,24.03,39.63C226.22,448.8,238.92,441.17,238.88,424.25z
M78.36,336.56c-0.07,16.35,12.18,35.46,26.64,41.57c13.6,5.74,24.53-1.52,24.14-16.28c-0.47-17.75-9.44-30.82-23.63-40.54
c-5.85-4.01-12.62-5.05-19.12-1.43C80,323.43,78.2,329.62,78.36,336.56z M78.16,216.83c1.81,17.43,9.33,31.66,25.03,40.21
c13.84,7.55,26.4-0.25,25.96-15.46c-0.51-17.56-9.43-30.51-23.26-40.31c-5.78-4.1-12.64-5.27-19.16-1.76
C80.09,203.09,78.12,209.49,78.16,216.83z"/>
</g>
<g>
<path class="st2" d="M438.48,269.36c0,23.88-0.09,47.77,0.04,71.65c0.08,14.95-5.66,26.05-19.04,33.69
c-45.56,26.01-90.87,52.43-136.3,78.66c-1.93,1.11-4.02,2.03-6.14,2.72c-4.13,1.36-6.9-0.45-7.9-4.42
c-0.69-2.73-0.78-5.65-0.78-8.49c-0.04-48.18,0.04-96.35-0.07-144.53c-0.03-14.73,6.49-25.32,19.04-32.56
c44.18-25.53,88.36-51.07,132.54-76.6c1.24-0.71,2.5-1.39,3.75-2.08c11.32-6.2,14.8-4.14,14.84,9.08
C438.53,220.78,438.48,245.07,438.48,269.36z M273.14,421.22c0.05,19.9,12.39,27.34,26.79,18.9
c14.92-8.75,23.03-22.32,24.24-39.46c1.09-15.44-12.22-24.3-25.6-16.81C282.99,392.57,274.73,406.59,273.14,421.22z
M273.19,300.58c-0.25,19.57,10.43,26.62,25.43,19.95c14.02-6.23,26.59-26.94,25.75-42.41c-0.77-14.26-13.04-21.55-25.73-14.51
C283.1,272.22,275.12,286.19,273.19,300.58z M378.55,373.28c0.05-21.14-11.77-28.95-25.77-20.61
c-15.26,9.09-24.61,22.51-24.5,41.07c0.1,15.52,11.79,22.77,25.39,15.25C369.25,400.38,377.63,386.78,378.55,373.28z
M433.65,340.47c0.1-20.18-12.26-27.99-26.62-19.24c-14.51,8.85-23.33,22.09-24,39.66c-0.62,16.14,11.34,23.92,25.59,16.37
C424.57,368.82,431.83,354.54,433.65,340.47z M378.56,249.19c0.11-16.72-10.87-24.46-24.88-17.53
c-15.12,7.48-26.59,27.54-25.35,44.37c0.88,11.94,10.06,18.07,21.51,14.37C365.3,285.38,378.44,266.54,378.56,249.19z
M433.67,217.08c0.11-15.23-9.9-22.9-23.27-17.86c-16.2,6.12-29.92,29.74-27.12,46.71c1.73,10.53,10.4,15.95,20.67,12.93
C419.6,254.24,433.54,234.65,433.67,217.08z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_actor">
<g>
<g>
<g>
<path class="st2" d="M194.72,240.85c-18.71-10.84-37.43-21.65-56.1-32.56c-4.38-2.56-3.72-6.78-3.09-10.93
c4.53-29.87,16.49-56.68,33.54-81.37c22.53-32.64,51.22-59.09,83.04-82.38c1.94-1.42,4.08-2.55,6.44-4.01
c2.95,1.91,5.76,3.52,8.35,5.44c34.2,25.36,64.61,54.39,87.21,90.87c13.92,22.47,23.34,46.63,27.11,72.93
c0.74,5.19-0.6,8.42-5.19,11.05c-17.12,9.83-34.08,19.93-51.1,29.92c-0.35-0.42-0.7-0.84-1.06-1.26
c7.2-7.59,13.9-15.74,21.74-22.61c6.97-6.11,8.08-12.73,6.54-21.27c-5.03-27.96-18.41-51.68-36.13-73.32
c-14.99-18.3-32.86-33.43-51.91-47.27c-3.26-2.37-6.29-3.56-10-0.89c-28.94,20.8-54.74,44.63-72.73,75.88
c-9.25,16.07-15.58,33.21-17.65,51.81c-0.5,4.49,0.65,7.78,3.76,10.99c9.23,9.52,18.23,19.25,27.32,28.9L194.72,240.85z"/>
</g>
<g>
<path class="st2" d="M168.55,345.65c-12.76,3.01-23.81-2.22-35.94-5.83c-3.63,12.02-1.15,22.71,4.28,33.16
c-0.52,0.49-1.04,0.98-1.56,1.47c-7.28-3.95-14.57-7.89-22.66-12.28c-0.94,40.71,5.85,79.96,12.76,120.22
c-9.73,0-18.21,0-28.31,0c0-4.71-0.17-8.65,0.03-12.57c2.77-54.5,0.73-108.5-16.69-160.88c-1.7-5.12-1.02-8.86,2.98-12.56
c15.25-14.13,30.3-28.49,45.51-42.67c1.86-1.73,4.21-2.92,7.2-4.95c12.66,31.79,36.38,51.55,65.92,65.71
c-23.56,4.18-43.99-5.23-64.98-14.12C142.45,319.03,153.45,333.5,168.55,345.65z"/>
</g>
<g>
<path class="st2" d="M378.56,342.15c-11.2,1.29-21.2,6.91-34.38,4.02c17.38-13.12,29.62-28.02,35.34-49.86
c-22.86,11.18-44.29,22.27-69.86,17.87c29.22-14.58,53.47-34,65.19-66.51c3.09,2.11,5.44,3.31,7.29,5.04
c15.49,14.48,30.83,29.13,46.36,43.57c3.94,3.66,4.92,7.36,3.13,12.52c-12.8,37.05-17.33,75.43-17.57,114.4
c-0.11,17.53,0.54,35.07,0.78,52.6c0.02,1.77-0.35,3.55-0.66,6.4c-8.97,0-17.6,0-27.36,0c6.32-39.97,13.54-79.18,12.38-120.61
c-8.84,4.81-16.27,8.85-23.71,12.89c-0.49-0.48-0.97-0.96-1.46-1.44C378.33,363.41,381.6,353.68,378.56,342.15z"/>
</g>
<g>
<path class="st2" d="M207.81,179.57c3.71-5.83,8.78-8.93,15.2-8.75c5.91,0.17,10.65,3.14,13.82,8.68
c-3.37,5.93-8.7,7.74-14.45,7.81C216.53,187.39,211.48,185.04,207.81,179.57z"/>
</g>
<g>
<path class="st2" d="M277.66,179.72c3.23-6.12,7.85-9.04,14-9c6.15,0.04,10.67,3.08,13.58,8.58c-2.43,6.15-7.58,7.55-12.87,7.82
C286.5,187.42,281.29,185.46,277.66,179.72z"/>
</g>
<g>
<path class="st2" d="M194.81,240.77c0,0-0.08,0.08-0.08,0.08C194.72,240.85,194.81,240.77,194.81,240.77z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_scene" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M141.31,362.45c10.55-10.81,21.11-21.61,32.39-33.17c-4.23-4.4-7.78-8.52-11.78-12.13
c-4.39-3.96-5.23-7.87-1.64-12.78c2.36-3.24,4.31-6.78,7.52-11.92c29.68,29.65,58.51,58.45,88.28,88.2
c29.63-29.58,58.38-58.28,88.43-88.27c3.76,6.48,7.17,11.44,9.48,16.88c0.68,1.6-1.26,4.92-2.82,6.75
c-3.78,4.43-8.04,8.45-12.61,13.15c3.87,4.06,7.01,7.46,10.26,10.75c6.02,6.1,12.2,12.04,18.09,18.27
c1.5,1.58,2.14,3.98,2.19,6.78c-11.12-2.35-15.32-13.36-25.7-18.87c-4.53,5.37-9.27,11-14.4,17.08
c4.03,8.46,15.77,12.55,18.84,22.89c-0.64,0.7-1.28,1.4-1.92,2.1c-2.18-1.32-4.7-2.29-6.49-4.01
c-7.5-7.21-14.75-14.68-22.17-21.99c-1.69-1.67-3.67-3.05-6.41-5.3c-5.41,5.88-10.51,11.42-16,17.4
c1.57,1.94,2.93,3.92,4.6,5.61c7.3,7.42,14.75,14.69,22,22.16c1.66,1.71,2.69,4.01,3.13,6.87
c-10.84-2.35-15.01-13.32-25.2-18.68c-4.93,5.38-10.02,10.94-15.43,16.85c4.67,9.02,15.38,13.49,19.26,23.07
c-0.54,0.67-1.09,1.34-1.63,2.01c-2.14-1.31-4.59-2.29-6.35-3.98c-7.49-7.22-14.75-14.69-22.17-21.99
c-1.69-1.66-3.68-3.01-5.89-4.79c-3.8,3-7.23,5.71-11.03,8.71c-3.77-2.97-7.19-5.68-11.01-8.69c-2.19,1.75-4.19,3.08-5.87,4.74
c-7.42,7.3-14.69,14.75-22.16,22c-1.73,1.67-4.02,2.76-6.91,3.23c2.31-10.77,13.12-15.02,18.63-25.24
c-5.42-4.76-11.09-9.74-17.21-15.11c-8.81,4.1-12.9,15.32-22.79,18.83c-0.62-0.47-1.25-0.95-1.87-1.42
c1.25-2.13,2.15-4.6,3.81-6.33c7.21-7.5,14.68-14.75,21.99-22.17c1.67-1.7,3.05-3.67,5.27-6.37
c-5.69-5.59-11.06-10.87-16.79-16.51c-2.48,2-4.47,3.36-6.16,5.02c-7.42,7.3-14.69,14.75-22.16,22c-1.71,1.66-4,2.72-6.87,3.19
c2.16-10.9,13.44-14.89,18.41-25.47c-5.23-4.81-10.76-9.89-16.39-15.06c-9.69,4.24-13.75,16.43-24.15,19.15
C143.03,364.74,142.17,363.6,141.31,362.45z"/>
</g>
<g>
<path class="st2" d="M441,403.48c-16.69-27.59-33.44-55.13-50.04-82.77c-42.46-70.68-84.85-141.39-127.26-212.1
c-1.34-2.23-2.47-4.58-4.3-8.02c13.34-3.15,24.63-8.77,32.97-20.46c1.71,2.53,2.89,3.85,3.6,5.4
c28.28,61.55,56.51,123.12,84.77,184.68c19.15,41.72,38.37,83.41,57.51,125.14c1.18,2.58,1.92,5.36,2.86,8.04L441,403.48z"/>
</g>
<g>
<path class="st2" d="M217.61,82.38c2.39,3.13,3.85,4.73,4.95,6.53c4.59,7.48,8.69,15.3,13.71,22.47
c4.35,6.21,4.12,11.18,0.16,17.73c-47.28,78.28-94.26,156.74-141.31,235.16c-6.51,10.85-13.01,21.71-19.54,32.55
c-1.13,1.88-2.39,3.68-4.72,4.92C119.57,295.76,168.27,189.77,217.61,82.38z"/>
</g>
<g>
<path class="st2" d="M477.25,255.92c-10.87-10.64-21.54-21.09-32.91-32.23c-5.58,5.75-10.68,11.01-16.24,16.75
c1.84,2.26,3.31,4.39,5.1,6.21c7.43,7.56,15,15,22.43,22.56c2.12,2.16,4.52,4.52-0.17,8.58c-7.22-6.76-14.48-13.55-21.88-20.47
c-6.08,5.51-11.66,10.57-17.97,16.3c7.88,8.42,14.65,15.65,21.42,22.88c-0.62,0.85-1.25,1.7-1.87,2.56
c-2.14-1.03-4.53-1.72-6.36-3.13c-13.8-10.59-21.18-25.52-27.46-41.16c-5.78-14.38-8.33-11.03,4.45-23.75
c7.23-7.19,14.4-14.44,21.65-21.61c1.71-1.69,3.62-3.17,5.84-5.08c1.73,1.12,3.41,1.86,4.63,3.06
c13.32,13.21,26.59,26.48,39.81,39.79C479.85,249.34,482.22,251.73,477.25,255.92z"/>
</g>
<g>
<path class="st2" d="M68.55,223.56c-12.92,10.59-22.16,23.11-34.32,32.22c-0.78-0.53-1.57-1.06-2.35-1.59
c0.43-1.85,0.25-4.3,1.39-5.46c14.33-14.51,28.84-28.83,43.34-43.18c0.39-0.38,1.12-0.42,1.97-0.71
c0.75,0.34,1.86,0.54,2.53,1.2c10.88,10.75,21.84,21.43,32.39,32.51c1.47,1.54,1.83,5.55,0.94,7.69
c-4.29,10.36-8.17,21.11-14.15,30.47c-5.16,8.08-12.9,14.53-19.62,21.58c-0.65,0.69-2.18,0.54-5.2,1.2
c3.65-11.71,15.03-15.79,20.22-26.77c-5.23-4.62-10.83-9.57-16.64-14.7c-9.41,4.67-13.78,15.49-23.35,19.4
c-0.67-0.54-1.35-1.07-2.02-1.61c1.11-1.99,1.87-4.32,3.4-5.91c7.07-7.35,14.38-14.47,21.55-21.72c1.84-1.86,3.48-3.92,6.4-7.23
C79.61,235.25,74.35,229.69,68.55,223.56z"/>
</g>
<g>
<path class="st2" d="M256.05,428.1c7.93,7.53,16.37,15.55,24.7,23.47c-8.21,8.27-16.4,16.51-24.37,24.54
c-8.23-7.98-16.67-16.16-25.11-24.34C239.8,443.62,248.21,435.58,256.05,428.1z"/>
</g>
<g>
<path class="st2" d="M254.88,73.27c6.48-5.93,12.68-11.6,18.52-16.94C275.4,65.47,265.2,75.93,254.88,73.27z"/>
</g>
<g>
<path class="st2" d="M238.87,49.47c0.54-7.99,6.12-13.62,15.88-13.57c-4.81,4.98-9.61,9.96-14.42,14.93
C239.84,50.38,239.35,49.92,238.87,49.47z"/>
</g>
<g>
<polygon class="st2" points="441.11,403.38 441.22,403.67 441,403.48 "/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_item" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M86.57,379.95c0-48.58,0-96.33,0-143.79c5.64-2.82,112.01-3.19,119.52-0.33c0.25,2.68,0.79,5.83,0.8,8.98
c0.07,26.94,0.01,53.88,0.08,80.83c0.01,3.17,0.51,6.33,0.85,10.3c32.36,0,63.92,0,97.01,0c0-33.87,0-66.95,0-99.19
c6.41-3.36,112.58-3.86,119.48-1.35c2.55,5.28,2.8,137.43-0.09,144.56C312.19,379.95,199.8,379.95,86.57,379.95z"/>
</g>
<g>
<path class="st2" d="M351.95,96.52c0,37.52,0,74.24,0,111.87c-15.41,0-30.07,0-45.61,0c-0.81-5.04-1.56-9.72-2.59-16.15
c-31.78-0.12-63.35-0.24-95.41,0.16c-1.01,5.85-1.81,10.52-2.76,16c-15.49,0-30.54,0-46.27,0c-0.48-3.17-1.18-5.7-1.19-8.24
c-0.08-31.43-0.09-62.85-0.03-94.28c0.02-8.73,1.64-10.33,10.48-10.33c58.36-0.05,116.72-0.03,175.09,0.01
C346.04,95.56,348.42,96.09,351.95,96.52z"/>
</g>
<g>
<path class="st2" d="M132.51,208.42c-9.52,0-18.03,0-27.47,0c0-37.52,0-74.16,0-111.86c9.22,0,17.87,0,27.47,0
C132.51,133.9,132.51,170.54,132.51,208.42z"/>
</g>
<g>
<path class="st2" d="M378.57,96.39c10.31,0,18.82,0,29.12,0c0.27,37.43,0.14,74.07,0.08,111.82c-10.01,0-18.66,0-29.13,0
C378.39,170.99,378.51,134.35,378.57,96.39z"/>
</g>
<g>
<path class="st2" d="M107.03,407.31c99.7,0,198.42,0,297.14,0c0.31,0.74,0.62,1.47,0.93,2.21c-3.8,2.18-7.48,4.61-11.44,6.42
c-1.72,0.78-4.02,0.36-6.06,0.36c-87.72,0.01-175.44-0.01-263.17,0.06C117.35,416.37,111.13,415.25,107.03,407.31z"/>
</g>
<g>
<path class="st2" d="M280.03,311.38c-16.62,0-31.68,0-47.61,0c0-31.35,0-61.94,0-93.7c15.6-1.68,30.82-0.85,47.53-0.45
C280.76,248.97,280.56,279.53,280.03,311.38z M267.36,293.14c0.39-3.77,0.85-6.35,0.89-8.94c0.12-7.13-0.2-14.28,0.21-21.39
c0.17-2.85,1.14-6.13,2.88-8.31c8.15-10.27,8.56-19.5,0.67-27.25c-8.45-8.3-21.51-8.87-30.61-1.33
c-8.41,6.98-10.24,17.21-3.09,25.35c4.73,5.38,5.6,10.91,5.4,17.36c-0.17,5.7-0.14,11.42,0.05,17.12
c0.08,2.32,0.82,4.63,1.34,7.39C252.64,293.14,259.56,293.14,267.36,293.14z"/>
</g>
<g>
<path class="st2" d="M459.64,208.46c-9.05,0-17.17,0-26.05,0c-0.44-3.46-1.09-6.2-1.09-8.93c-0.07-31.16-0.05-62.33-0.04-93.49
c0-1.22,0.07-2.44,0.15-3.66c0.3-4.41,2.7-6.57,7.1-6.7c4.5-0.13,6.66,2.09,7.24,6.46c4.34,32.91,8.76,65.81,13.07,98.73
C460.3,202.98,459.83,205.2,459.64,208.46z"/>
</g>
<g>
<path class="st2" d="M77.56,97.23c0,36.74,0,73.41,0,111.08c-8.48,0-16.35,0-25.02,0c-0.25-2.71-0.9-5.08-0.6-7.34
c4.21-32.52,8.49-65.04,12.9-97.53C65.84,96.02,68.83,94.5,77.56,97.23z"/>
</g>
<g>
<path class="st2" d="M451.71,362.72c0-42.84,0-84.74,0-127.72c3.45-0.21,6.42-0.39,10.08-0.61c0.46,3.5,1.09,6.04,1.1,8.58
c0.06,34.46-0.08,68.92,0.12,103.38C463.06,354.24,458.99,358.62,451.71,362.72z"/>
</g>
<g>
<path class="st2" d="M50.26,234.87c2.86,0,5.32,0,7.56,0c2.47,5.02,3.24,118.46,0.9,126.79c-5.37-3.13-9.67-6.58-9.66-13.41
c0.02-35.65-0.01-71.31,0.05-106.96C49.12,239.34,49.79,237.4,50.26,234.87z"/>
</g>
<g>
<path class="st2" d="M51.56,390.71c7.99,7.72,15.99,15.44,25.01,24.15c-9.12,2.16-16.82,2.02-24.49,0.42
c-1.03-0.21-2.41-2.03-2.45-3.14c-0.23-6.78-0.11-13.57-0.11-20.36C50.2,391.43,50.88,391.07,51.56,390.71z"/>
</g>
<g>
<path class="st2" d="M436.46,413.79c8.05-7.65,16.1-15.3,24.15-22.95c0.61,0.34,1.23,0.69,1.84,1.03
c0,6.76,0.19,13.52-0.17,20.26c-0.07,1.29-2.24,3.46-3.53,3.53c-7.16,0.35-14.35,0.17-21.53,0.17
C436.96,415.15,436.71,414.47,436.46,413.79z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_fight" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M98.54,121.71c7.19,0.33,14.38,0.67,22.81,1.06c1.18-7.93,2.28-15.34,3.38-22.75
c0.65-0.23,1.3-0.46,1.95-0.69c70.17,84.04,140.34,168.07,211.57,253.38c-9.84,8.24-18.85,15.78-28.82,24.13
C238.18,291.6,167.84,207.47,97.5,123.34C97.85,122.8,98.2,122.26,98.54,121.71z"/>
</g>
<g>
<path class="st2" d="M74.25,462.04c-10.75-7.58-20.15-14.21-30.69-21.64C87.39,378.65,130.68,317.64,175,255.19
c8.95,10.7,16.69,19.95,24.95,29.82C158.02,344.06,116.54,402.48,74.25,462.04z"/>
</g>
<g>
<path class="st2" d="M425.22,103.01c0.37,2.17,1.08,4.12,0.96,6.02c-1.52,23.89-10.41,44.55-26.71,62.21
c-17.85,19.34-40.04,31.93-63.81,42.21c-1.98,0.86-4.11,1.36-7.64,2.49c1.24-4.12,1.91-6.97,2.94-9.69
c6.52-17.26,11.93-34.75,11.33-53.5c-0.09-2.84-0.01-5.86-0.93-8.47c-2.37-6.7,0.06-11.13,5.24-15.36
c8.52-6.96,16.52-14.54,24.94-21.63c1.91-1.61,4.59-3.05,6.99-3.2c14.23-0.85,28.48-1.32,42.72-1.86
C422.24,102.2,423.23,102.61,425.22,103.01z"/>
</g>
<g>
<path class="st2" d="M291.85,453.14c-4.87-5.91-8.93-10.84-14.08-17.09c41.71-34.89,82.71-69.18,124.58-104.2
c4.79,5.78,8.96,10.8,14.01,16.89C374.53,383.82,333.55,418.17,291.85,453.14z"/>
</g>
<g>
<path class="st2" d="M273.79,115.61c10.76,7.57,20.25,14.24,30.73,21.61c-17.52,24.77-34.23,48.41-51.86,73.34
c-8.76-10.27-16.69-19.55-25.21-29.54C242.84,159.29,257.83,138.14,273.79,115.61z"/>
</g>
<g>
<path class="st2" d="M310.02,250.99c3.13-1.7,6.08-3.97,9.41-5.02c21.89-6.92,42.92-15.68,62.36-28.02
c29.04-18.43,51.93-42.06,63.17-75.38c4.67-13.85,6.52-28.16,6.18-42.77c-0.05-2.01-0.01-4.02-0.01-6.78
c3.9-2.17,7.86-4.37,12.69-7.05c1.31,3.33,2.56,5.61,3.12,8.05c3.1,13.52,1.31,26.78-2.57,39.85
c-16.18,54.48-81.45,113.08-140.32,120.1c-4.27,0.51-8.65,0.07-12.98,0.07C310.71,253.03,310.37,252.01,310.02,250.99z"/>
</g>
<g>
<path class="st2" d="M389.79,472.78c-11.28-13.51-21.9-26.23-33.01-39.54c8.13-9.93,17.68-16.81,28.3-24.44
c11.08,13.21,21.71,25.89,33.02,39.37C409.83,457.64,400.05,464.37,389.79,472.78z"/>
</g>
<g>
<path class="st2" d="M321.15,118.13c-11.98-8.39-23.18-16.22-35.16-24.61c4.46-12.23,8.63-23.66,13.37-36.67
c17.45,12.36,33.25,23.54,50.46,35.73C339.82,101.49,330.87,109.47,321.15,118.13z"/>
</g>
<g>
<path class="st2" d="M98.58,95.77c-7.12-0.81-13.28-1.35-19.35-2.36c-1.23-0.2-2.8-2.02-3.15-3.37
c-2.23-8.67-4.18-17.41-6.14-26.14c-0.15-0.68,0.35-1.51,0.74-2.98c1.89,0.47,3.64,0.68,5.2,1.33
c6.2,2.59,12.29,5.47,18.53,7.94c4.9,1.94,7.04,5.25,6.33,10.43C100.13,85.01,99.49,89.39,98.58,95.77z"/>
</g>
<g>
<path class="st2" d="M263.6,72.75c-4.58-8.72-9.17-17.44-14.34-27.29c9.64-1.5,17.2,0.6,26.32,3.04
c-3.26,8.72-6.26,16.73-9.26,24.75C265.41,73.08,264.5,72.92,263.6,72.75z"/>
</g>
<g>
<path class="st2" d="M328.1,39.22c10.42,7.7,21.69,12.69,29.96,23.17C349.73,64.21,326.41,46.59,328.1,39.22z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_compendium" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M172.73,49.37c21.98,0,43.98,0,66.87,0c0,137.52,0,274.28,0,412.73c-22.56,0.64-44.71,0.55-66.23,0.05
C170.22,455.66,169.78,57.56,172.73,49.37z M200.52,429.88c3.18-7.29,2.79-312.57-0.29-318.12c-6.66,0-13.58,0-20.13,0
c-3.18,7.31-2.79,312.56,0.29,318.12C187.06,429.88,193.98,429.88,200.52,429.88z M210.72,299.22
c-3.15,7.38-2.74,125.16,0.33,130.65c6.67,0,13.59,0,21.35,0c0-43.84,0-86.81,0-130.65
C224.64,299.22,217.72,299.22,210.72,299.22z"/>
</g>
<g>
<path class="st2" d="M145.38,142.76c0,85.62,0,170.31,0,256.67c-17.42,1.03-34.25,0.66-51.8,0.12
c-0.49-3.88-1.14-6.62-1.14-9.36c-0.05-79.17-0.06-158.34-0.03-237.52c0-9.54,1.47-10.94,11.07-11
c11.02-0.07,22.04-0.07,33.06,0.03C139.11,141.74,141.67,142.3,145.38,142.76z"/>
</g>
<g>
<path class="st2" d="M363.52,456.03c-12.7,2.35-23.74,4.39-35.68,6.6c-1.26-4.11-2.57-7.24-3.16-10.5
c-10.85-60.07-21.6-120.15-32.38-180.23c-7.75-43.2-15.53-86.4-23.26-129.6c-0.49-2.72-0.59-5.51-1-9.55
c12.13-2.2,23.57-4.27,36.31-6.58C324.11,236.33,343.65,345.24,363.52,456.03z"/>
</g>
<g>
<path class="st2" d="M30.77,95.93c12.29,0,23.52,0,35.63,0c0.49,3.12,1.29,5.83,1.29,8.53c0.07,53.47,0.07,106.95,0.02,160.42
c0,2.37-0.57,4.75-0.98,8c-11.97,0-23.53,0-35.96,0C30.77,213.88,30.77,155.54,30.77,95.93z"/>
</g>
<g>
<path class="st2" d="M367.58,238.23c7-3.03,12.81-5.54,20.08-8.69c31.66,74.22,62.88,147.39,94.52,221.55
c-7.17,3.14-12.98,5.68-20.06,8.77C430.48,385.69,399.26,312.48,367.58,238.23z"/>
</g>
<g>
<path class="st2" d="M65.98,461.62c-11.43,0-22.81,0-35.96,0c-0.23-38.48-0.1-76.1-0.08-114.56c13.02,0,24.42,0,35.56,0
C68.27,352.44,68.8,453.4,65.98,461.62z"/>
</g>
<g>
<path class="st2" d="M145.31,461.62c-17.64,0-34.34,0-51.98,0c0-12.22,0-23.59,0-34.65c5.83-2.99,44.82-3.3,51.98-0.36
C145.31,437.66,145.31,449.07,145.31,461.62z"/>
</g>
<g>
<path class="st2" d="M66.94,299.04c0,7.68,0,14,0,20c-5.68,3.23-28.48,3.6-36.48,0.32c0-5.15-0.23-10.92,0.17-16.64
c0.09-1.3,2.32-3.48,3.61-3.52C44.72,298.91,55.21,299.04,66.94,299.04z"/>
</g>
<g>
<path class="st2" d="M344.77,183.51c1.37-6.24,13.25-11.41,18.86-8.56C361.93,179.91,351.56,184.78,344.77,183.51z"/>
</g>
<g>
<path class="st2" d="M376.69,203.79c-1.47,1.58-2.66,3.99-4.46,4.57c-4.85,1.58-9.26,6.71-16.33,2.77
c5.69-6.11,12.27-7.7,18.8-9.41C375.37,202.41,376.03,203.1,376.69,203.79z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_settings" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M167.35,468.66c-13.39-1.77-50.61-24-55.69-33.14c1.08-1.73,2.27-3.8,3.62-5.75
c9.08-13.11,15.46-27.19,17.17-43.32c2.08-19.66-8.6-38.21-26.93-45.65c-18.45-7.49-36.8-5.28-55.13,0.52
c-2.27,0.72-4.61,1.24-7.95,2.13c-8.74-20.07-13.97-40.42-16.04-62.21c3.72-1,6.27-1.51,8.71-2.36
c10.15-3.55,20.93-5.98,30.28-11.03c32.02-17.29,37.2-51.45,11.57-77.58c-7.69-7.84-18.02-13.11-27.21-19.46
c-1.8-1.24-3.88-2.08-6.88-3.65c7.46-20.81,19.04-38.63,32.65-56.07c2.6,1.58,4.49,2.63,6.28,3.83
c12.84,8.66,26.44,15.16,42.16,16.87c27.62,3.01,49.81-16.05,50.75-43.89c0.44-12.98-0.7-25.69-5.26-37.95
c-0.57-1.52-0.94-3.13-1.27-4.72c-0.16-0.77-0.03-1.6-0.03-3.56c19.48-9.06,40.19-13.46,62.14-15.74
c1.02,3.75,1.82,6.21,2.34,8.72c3.47,16.64,9.06,32.26,21.51,44.52c15.73,15.49,38.24,17.59,56.71,5.52
c12.09-7.9,21.07-18.51,27.72-31.22c1.77-3.4,3.56-6.79,5.82-11.11c21.09,7.8,39.67,18.42,56.8,32.93
c-1.64,2.8-2.68,4.95-4.05,6.86C388.21,94.64,382,108.15,380,123.56c-3.04,23.55,11.24,44.26,34.61,49.71
c15.81,3.69,31.2,1.62,46.42-3.22c2.48-0.79,5-1.42,8.46-2.39c8.98,19.98,13.9,40.42,16.18,62.37c-3.8,0.94-6.46,1.76-9.18,2.25
c-16.65,3.01-31.7,9.36-43.86,21.42c-17.55,17.41-17.87,44.76-1.08,62.94c9.09,9.85,19.19,18.29,31.47,23.91
c1.97,0.9,3.73,2.29,6.35,3.94c-7.98,20.35-18.77,38.4-32.84,55.12c-3.06-1.75-5.24-2.79-7.18-4.15
c-11.9-8.34-24.87-13.72-39.36-15.81c-25.9-3.73-48.07,12.39-52.41,38.17c-2.51,14.96-0.26,29.24,4.49,43.36
c0.89,2.64,1.57,5.34,2.63,8.96c-20.39,9.22-41.13,13.92-63.52,15.93c-1.27-5.66-2.36-10.56-3.47-15.47
c-2.68-11.93-7.48-22.97-15.18-32.45c-19.22-23.66-48.23-25.35-70.63-3.31c-8,7.87-13.67,18.12-20.35,27.33
C170.02,464.25,168.74,466.5,167.35,468.66z M255.86,400.9c76.17,1.14,145.09-60.6,145.17-144.58
c0.07-81.43-64.18-146.3-147.02-145.43c-80.82,0.84-143.17,67.24-143.11,145.2C110.95,336.29,175.57,400.89,255.86,400.9z"/>
</g>
<g>
<path class="st2" d="M255.9,375.07c-66.32-0.01-119.05-52.79-119.18-119.01c-0.12-60.41,46.51-119.03,119.17-119.37
c66.88-0.31,119,51.98,119.5,119.66C375.87,322.28,322.28,375.08,255.9,375.07z M256.32,367.82
c61.81,0.01,112.28-50.05,111.82-111.65c-0.45-60.76-47.78-111.81-111.76-112.13c-63.11-0.31-112.37,51.07-112.41,112.06
C143.95,318.19,193.87,367.82,256.32,367.82z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_journal" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M448.42,92.12c-17.01,7.17-36.38,3.32-52.81,13.34c13.35,7.59,25.04,14.25,36.73,20.9
c-0.07,0.7-0.15,1.39-0.22,2.09c-10.32,2.08-20.63,4.16-30.95,6.23c-0.13,0.63-0.27,1.25-0.4,1.88
c14.07,8.7,28.14,17.4,42.66,26.38c-0.79,3.42-1.29,6.39-2.17,9.24c-9.51,30.75-25.84,57.54-47.17,81.49
c-28.41,31.88-43.98,69.29-47.66,111.76c-0.21,2.39-0.8,4.75-1.37,8.08c-3.69,0.38-7.21,1.06-10.74,1.07
c-52.87,0.07-105.74-0.15-158.6,0.15c-23.87,0.13-41.44,11.18-51.15,33.28c-13.04,29.65,8.96,66.89,45.53,62.06
c6.73-0.89,13.59-0.76,20.39-1.1c0.18,0.69,0.36,1.39,0.54,2.08c-1.95,1.11-3.78,2.8-5.87,3.23
c-13.93,2.87-27.83,6.21-41.92,7.89c-9.63,1.15-19.71,0.93-29.3-0.54c-25.73-3.96-39.5-20.96-46.09-44.94
c-7.68-27.98-4.86-55.9,1.11-83.65c2.48-11.54,6.41-22.77,9.52-34.19c1.48-5.44,4.92-7.99,10.38-8.84
c14.32-2.22,28.6-4.7,42.88-7.15c2.31-0.4,4.55-1.17,8.35-2.18c-12.43-12.92-23.92-24.85-35.68-37.07
c10.82-18.72,21.31-36.6,31.53-54.63c10.13-17.88,18.72-36.44,25.46-57.28c-4.1-0.52-6.79-1.1-9.48-1.17
c-19.98-0.48-39.99-0.43-59.95-1.38c-24.37-1.15-41.44-13.86-51.3-35.78c-9.41-20.93-7.08-40.88,7.01-59.34
c19.06-24.97,49.5-32.54,79.33-22.79c21.47,7.01,43.03,8.54,65.03,9.07c24.68,0.59,49.38,1.73,74.03,1.02
c37.08-1.07,74.08-3.17,111.05-7.28c35.35-3.93,63.98,16.8,71.28,52.84C448.69,88.4,448.42,90.05,448.42,92.12z M159.2,70.78
c0-1.99,0.18-2.66-0.04-3.16c-0.48-1.12-1.19-2.13-1.74-3.22c-6.25-12.36-16.75-18.76-29.81-22.21
c-18.28-4.83-36.2-6.22-53.53,3.12c-21.82,11.76-31.94,33.41-26.21,55.84c5.97,23.41,24.48,37.29,49.57,37.18
c17.77-0.08,24.02-8.04,17.19-24.49c-5.04-12.13-12.63-23.2-19.09-34.74c-1.22-2.18-2.46-4.34-4.73-8.33
C114.8,70.78,137.01,70.78,159.2,70.78z M125.86,137.58c1.23,0.84,1.72,1.47,2.22,1.47c10.98,0.11,21.98,0.38,32.94-0.05
c1.75-0.07,4.42-3.12,4.9-5.2c3.31-14.42,3.93-28.99,1.39-43.67c-1-5.82-3.9-8.4-9.91-8.3c-12.83,0.22-25.67,0.01-38.51,0.11
c-2.02,0.02-4.04,0.76-6.94,1.34C121.1,101.11,132.77,117.32,125.86,137.58z"/>
</g>
<g>
<path class="st2" d="M437.3,403.69c-12.05,6.13-24.1,12.27-36.16,18.4c0.06,0.71,0.11,1.41,0.17,2.12
c24.23,2.92,48.45,5.83,72.88,8.77c0.85,2.39,1.74,4.21,2.15,6.14c4.1,19.37-9.24,40.07-28.6,44.05
c-5.16,1.06-10.51,1.63-15.78,1.64c-68.14,0.11-136.27,0.08-204.41,0.06c-2.4,0-4.79-0.23-9.27-0.46
c10.87-12.42,17.06-25.54,17.43-40.56c0.37-14.77-2.14-29.17-10.26-43.31c3.8-0.56,6.28-1.23,8.77-1.24
c60.59-0.06,121.18-0.1,181.76,0.05c7,0.02,13.99,1.22,20.99,1.88C437.07,402.06,437.18,402.88,437.3,403.69z"/>
</g>
<g>
<path class="st2" d="M208.78,442.37c-2.84,0.3-5.59,0.73-8.35,0.86c-11.77,0.56-23.55,0.9-35.32,1.59
c-11.74,0.69-20.7-11.09-17.7-23.56c2.84-11.78,14.12-20.41,27.04-20.71C193.39,400.09,213.19,416.86,208.78,442.37z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_music" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M261.65,225.6c0.7,2.64,1.55,5.26,2.07,7.94c1.62,8.25,2.65,8.79,11.01,8.46c15-0.58,29.14,2.2,41.74,11.16
c14.6,10.37,19.64,25.5,21.71,42.14c2.78,22.32-10.19,36.76-25.52,49.9c-0.44,0.37-1.09,0.54-1.67,0.69
c-0.37,0.09-0.8-0.03-1.59-0.08c-3.15-4.92-2.8-9.59,0.96-14.33c6.14-7.74,11.54-15.89,12.05-26.24
c1.24-25.02-14.28-44.09-39.26-47.94c-4.59-0.71-9.31-0.53-15-0.81c0.44,4.72,0.51,7.73,1.03,10.66
c8.8,49.42,17.66,98.83,26.47,148.26c1.07,6.03,2.01,12.08,2.81,18.15c1.93,14.59-2.85,26.51-14.6,35.46
c-18.51,14.1-39.18,15.5-60.44,8.72c-16.02-5.1-25.76-22.74-22.74-38.34c3.49-18.02,17.24-29.36,35.42-29.2
c17.96,0.16,31.41,11.98,34.49,30.27c0.42,2.52,1.01,5.02,1.49,7.33c10.2,0.4,17.08-7.88,15.5-18.5
c-3.27-22-6.51-44.01-10.45-65.89c-5.72-31.73-12.04-63.35-18.15-95.01c-0.4-2.07-1.27-4.05-2.29-7.23
c-7.24,4.84-12.49,9.93-15.47,17.08c-5.54,13.32-3.63,26.35,1.74,39.25c1.25,3.01,1.98,6.23,2.95,9.35
c-0.69,0.48-1.39,0.96-2.08,1.44c-1.98-1.63-4.28-2.98-5.89-4.92c-14.99-18.11-14.14-48.78,1.75-66.18
c2.06-2.26,4.06-4.69,6.52-6.45c5.79-4.17,9.56-8.69,8.28-16.73c-0.43-2.71,3.11-6.04,4.83-9.09
C260.1,225.14,260.88,225.37,261.65,225.6z"/>
</g>
<g>
<path class="st2" d="M242.98,129.77c-0.54-2.18-1.24-3.66-1.24-5.15c0.06-27.65,5.24-53.97,20.63-77.55
c0.78-1.19,1.62-2.36,2.52-3.47c15.38-18.96,34.82-17.62,45.72,4.2c15.14,30.31,13.51,60.55-6.91,87.73
c-13.67,18.2-29.81,34.59-45.42,51.26c-18.14,19.38-36.83,38.27-50.39,61.34c-4.74,8.07-9.5,16.33-12.73,25.07
c-8.46,22.81-4.26,43.77,11.57,62.22c9.81,11.44,22.06,19.31,36.6,23.44c5.39,1.53,7.9,4.61,6.35,11.29
c-2.86,0-5.84,0.44-8.66-0.07c-31-5.57-50.06-25.12-60.87-53.46c-11.63-30.51-8.06-59.85,11.23-86
c15.34-20.81,32.18-40.57,49.3-59.97c15.92-18.03,33.27-34.79,49.64-52.44c11.16-12.03,12.87-27,10.85-42.48
c-1.06-8.1-5.98-13.73-14.13-16.01c-7.39-2.07-12.75,1.54-17.1,6.79c-2.57,3.1-5.27,6.57-6.35,10.32
c-3.64,12.7-7.02,25.51-9.61,38.46C252.62,122.04,249,126,242.98,129.77z"/>
</g>
</g>
</g>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><defs><radialGradient id="darkzaitzev-hooded-figure-gradient-2"><stop offset="0%" stop-color="#b8e986" stop-opacity="1"></stop><stop offset="100%" stop-color="#ffe0af" stop-opacity="1"></stop></radialGradient><linearGradient x1="0" x2="0" y1="0" y2="1" id="darkzaitzev-hooded-figure-gradient-5"><stop offset="0%" stop-color="#417505" stop-opacity="1"></stop><stop offset="100%" stop-color="#8b572a" stop-opacity="1"></stop></linearGradient></defs><g class="" transform="translate(1,0)" style=""><path d="M355.102 21.097c-33.682.164-64.173 18.585-74.615 50.5 21.357-.79 23.203 53.922 23.203 53.922l41.619 6.262c-13.41 12.963-50.025 5.967-50.025 5.967-17.14 19.182-33.124 40.966-47.758 57.578-15.952 18.127-35.2 38.103-57.018 60.086-6.79 6.823 41.594-9.821 34.342-2.604-24.567 12.751-42.297 16.097-61.764 32.069-31.312 25.674-62.853 60.71-81.146 79.431-7.711 7.91-44.362 37.674 20.469 34.74 2.404 7.52-1.621 9.456-7.493 15.293-4.327 4.303-18.082.283-22.263 2.828-22.172 35.055-17.246 37.975-27.43 58.047-4.252 11.635 41.68-14.404 64.305-34.18 13.974-7.58 25.147-21.652 35.002-17.202 43.11 18.984 129.826 35.53 141.328 27.619 18.368-12.646-10.321-46.343 3.832-97.912 23.47 5.817 43.825 13.657 66.767 11.459-1.581 49.307 3.56 55.306-3.888 104.777l59.129 21.127 1.91-13.809-33.815-22.478c14.568-50.659 16.809-72.578 15.227-121.719-.16-5.372-45.168-24.325-74.492-33.133l18.593-30.412c30.393-44.788 124.141-62.055 127.932-88.258-13.02-19.676 3.022-27.384-25.092-21.912-6.295 1.318-13.771 24.346-18.023 27.213-7.843 5.276-40.655 24.477-51.951 18.377-1.9-1.026 7.246-33.441 6.85-44.78-.116-3.205-1.19-6.625-2.866-10.001.185-.64 15.24-52.482 54.809-94.016-43.978 25.134-65.332 79.925-65.354 79.98-2.207-2.134-4.476-3.983-6.639-5.423-1.916-14.7-4.819-73.02 68.598-78.776-21.427-21.177-47.704-30.78-72.283-30.66z" fill="#fff" fill-opacity="1" transform="translate(512, 0) scale(-1, 1) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -1,449 +1 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512.07 512" style="enable-background:new 0 0 512.07 512;" xml:space="preserve">
<style type="text/css">
.st0{display:none;}
.st1{display:inline;}
.st2{fill:#DCDCDC;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<g id="icon_x5F_sidebar_x5F_chat" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M180,480.93c14-15.25,27.95-29.3,40.56-44.47c14.18-17.05,23.54-36.69,26.34-59.05
c1.66-13.29-0.67-25.98-5.04-38.48c-1.8-5.15-5.7-5.52-10.23-5.78c-18.92-1.08-37.99-1.21-56.71-3.83
c-40-5.59-76.63-19.99-107.18-47.16c-36.18-32.19-46.99-77.73-26.93-122.29c15.37-34.14,40.96-59.17,71.93-78.94
c47.68-30.44,100.22-45.65,156.55-49.23c41.61-2.64,81.81,2.91,120.81,17.42c26.15,9.73,48.71,24.87,66.74,46.2
c29.1,34.42,32.23,80.62,8.86,120.58c-23.61,40.37-58.93,67.06-100.58,86.28c-10.17,4.7-20.81,8.38-31.3,12.36
c-4.3,1.63-6.47,4.24-6.8,9.02c-2.04,29.43-14.23,54.78-32.77,77.05c-29.18,35.06-66,59.86-107.6,77.9
C184.67,479.39,182.56,480.01,180,480.93z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_rolltable" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M255.1,55.46c6.7,2.37,12.64,3.53,17.63,6.38c47.83,27.36,95.49,55,143.19,82.58
c1.76,1.02,3.5,2.14,5.06,3.43c4.67,3.85,4.73,8.08-0.19,11.57c-4.48,3.18-9.3,5.9-14.07,8.66
c-43.81,25.34-87.68,50.58-131.43,76.01c-12.79,7.43-25.19,8.02-38.18,0.44c-47.26-27.53-94.66-54.81-141.95-82.29
c-11.67-6.78-11.5-10.86,0.17-17.61c45.93-26.57,91.78-53.27,137.82-79.64C240.07,61.03,247.84,58.57,255.1,55.46z
M256.6,177.07c8.18-2.74,15.83-4.76,23.02-7.85c6.75-2.9,11.12-8.42,11.32-16.12c0.2-7.86-4.55-13.18-10.98-16.36
c-16.34-8.07-32.92-8.99-48.94,0.93c-13.18,8.17-13.33,23.46,0.28,30.9C238.94,172.75,248.01,174.3,256.6,177.07z
M139.44,174.49c10.51,0.36,20.31-1.78,28.43-8.85c7.92-6.9,8.07-17.96,0.6-25.36c-13.09-12.97-44.39-13.07-57.62-0.19
c-8.94,8.7-8.15,19.73,2.02,27.08C120.8,172.91,129.82,174.83,139.44,174.49z M371.05,174.5c13.13,0.01,20.45-1.93,27.72-7.04
c11.22-7.88,11.04-21.8-0.38-29.44c-14.58-9.76-37.05-9.78-51.54-0.06c-11.6,7.78-11.75,21.98-0.23,29.88
C354.29,173.1,362.88,175.12,371.05,174.5z M257.2,200.1c-10.74-0.21-20.43,1.8-28.51,8.53c-9.63,8.02-9.2,19.91,0.7,27.6
c13.81,10.71,40.59,10.4,54.05-0.63c9.82-8.05,9.29-21.21-1.19-28.54C274.59,201.7,265.94,199.86,257.2,200.1z M255.77,105.95
c10.86-0.08,20.49-2.25,28.35-9.28c8.51-7.61,8.52-17.75,0.3-25.54c-13.52-12.81-43.78-12.59-57.1,0.4
c-7.45,7.27-7.44,17.61,0.19,24.78C235.62,103.93,245.78,105.61,255.77,105.95z"/>
</g>
<g>
<path class="st2" d="M73.56,270.29c-0.01-23.47-0.01-46.95,0-70.42c0-2.24-0.04-4.5,0.09-6.73c0.55-9.08,4.45-11.43,12.3-7.03
c14.77,8.29,29.43,16.78,44.1,25.25c31.29,18.06,62.49,36.27,93.87,54.16c13.59,7.75,19.9,19.03,19.84,34.61
c-0.18,47.56-0.07,95.12-0.07,142.68c0,1.02,0,2.04-0.03,3.06c-0.37,10.88-4.46,13.26-13.91,7.81
c-46.51-26.8-93.02-53.6-139.43-80.56c-11.08-6.44-16.76-16.38-16.77-29.35C73.56,319.28,73.57,294.79,73.56,270.29z
M238.89,301.12c-1.04-15.22-9.94-29.1-25.87-37.67c-12.78-6.88-25.53,0.97-25.17,15.07c0.45,18,8.76,32.2,24.15,41.47
C226.27,328.58,238.87,320.93,238.89,301.12z M238.88,424.25c-0.03-14.84-11.77-33.85-24.91-40.35
c-13.82-6.83-27.24,1.36-26.24,16.4c1.14,17.22,9.44,30.68,24.03,39.63C226.22,448.8,238.92,441.17,238.88,424.25z
M78.36,336.56c-0.07,16.35,12.18,35.46,26.64,41.57c13.6,5.74,24.53-1.52,24.14-16.28c-0.47-17.75-9.44-30.82-23.63-40.54
c-5.85-4.01-12.62-5.05-19.12-1.43C80,323.43,78.2,329.62,78.36,336.56z M78.16,216.83c1.81,17.43,9.33,31.66,25.03,40.21
c13.84,7.55,26.4-0.25,25.96-15.46c-0.51-17.56-9.43-30.51-23.26-40.31c-5.78-4.1-12.64-5.27-19.16-1.76
C80.09,203.09,78.12,209.49,78.16,216.83z"/>
</g>
<g>
<path class="st2" d="M438.48,269.36c0,23.88-0.09,47.77,0.04,71.65c0.08,14.95-5.66,26.05-19.04,33.69
c-45.56,26.01-90.87,52.43-136.3,78.66c-1.93,1.11-4.02,2.03-6.14,2.72c-4.13,1.36-6.9-0.45-7.9-4.42
c-0.69-2.73-0.78-5.65-0.78-8.49c-0.04-48.18,0.04-96.35-0.07-144.53c-0.03-14.73,6.49-25.32,19.04-32.56
c44.18-25.53,88.36-51.07,132.54-76.6c1.24-0.71,2.5-1.39,3.75-2.08c11.32-6.2,14.8-4.14,14.84,9.08
C438.53,220.78,438.48,245.07,438.48,269.36z M273.14,421.22c0.05,19.9,12.39,27.34,26.79,18.9
c14.92-8.75,23.03-22.32,24.24-39.46c1.09-15.44-12.22-24.3-25.6-16.81C282.99,392.57,274.73,406.59,273.14,421.22z
M273.19,300.58c-0.25,19.57,10.43,26.62,25.43,19.95c14.02-6.23,26.59-26.94,25.75-42.41c-0.77-14.26-13.04-21.55-25.73-14.51
C283.1,272.22,275.12,286.19,273.19,300.58z M378.55,373.28c0.05-21.14-11.77-28.95-25.77-20.61
c-15.26,9.09-24.61,22.51-24.5,41.07c0.1,15.52,11.79,22.77,25.39,15.25C369.25,400.38,377.63,386.78,378.55,373.28z
M433.65,340.47c0.1-20.18-12.26-27.99-26.62-19.24c-14.51,8.85-23.33,22.09-24,39.66c-0.62,16.14,11.34,23.92,25.59,16.37
C424.57,368.82,431.83,354.54,433.65,340.47z M378.56,249.19c0.11-16.72-10.87-24.46-24.88-17.53
c-15.12,7.48-26.59,27.54-25.35,44.37c0.88,11.94,10.06,18.07,21.51,14.37C365.3,285.38,378.44,266.54,378.56,249.19z
M433.67,217.08c0.11-15.23-9.9-22.9-23.27-17.86c-16.2,6.12-29.92,29.74-27.12,46.71c1.73,10.53,10.4,15.95,20.67,12.93
C419.6,254.24,433.54,234.65,433.67,217.08z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_actor" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M194.72,240.85c-18.71-10.84-37.43-21.65-56.1-32.56c-4.38-2.56-3.72-6.78-3.09-10.93
c4.53-29.87,16.49-56.68,33.54-81.37c22.53-32.64,51.22-59.09,83.04-82.38c1.94-1.42,4.08-2.55,6.44-4.01
c2.95,1.91,5.76,3.52,8.35,5.44c34.2,25.36,64.61,54.39,87.21,90.87c13.92,22.47,23.34,46.63,27.11,72.93
c0.74,5.19-0.6,8.42-5.19,11.05c-17.12,9.83-34.08,19.93-51.1,29.92c-0.35-0.42-0.7-0.84-1.06-1.26
c7.2-7.59,13.9-15.74,21.74-22.61c6.97-6.11,8.08-12.73,6.54-21.27c-5.03-27.96-18.41-51.68-36.13-73.32
c-14.99-18.3-32.86-33.43-51.91-47.27c-3.26-2.37-6.29-3.56-10-0.89c-28.94,20.8-54.74,44.63-72.73,75.88
c-9.25,16.07-15.58,33.21-17.65,51.81c-0.5,4.49,0.65,7.78,3.76,10.99c9.23,9.52,18.23,19.25,27.32,28.9L194.72,240.85z"/>
</g>
<g>
<path class="st2" d="M168.55,345.65c-12.76,3.01-23.81-2.22-35.94-5.83c-3.63,12.02-1.15,22.71,4.28,33.16
c-0.52,0.49-1.04,0.98-1.56,1.47c-7.28-3.95-14.57-7.89-22.66-12.28c-0.94,40.71,5.85,79.96,12.76,120.22
c-9.73,0-18.21,0-28.31,0c0-4.71-0.17-8.65,0.03-12.57c2.77-54.5,0.73-108.5-16.69-160.88c-1.7-5.12-1.02-8.86,2.98-12.56
c15.25-14.13,30.3-28.49,45.51-42.67c1.86-1.73,4.21-2.92,7.2-4.95c12.66,31.79,36.38,51.55,65.92,65.71
c-23.56,4.18-43.99-5.23-64.98-14.12C142.45,319.03,153.45,333.5,168.55,345.65z"/>
</g>
<g>
<path class="st2" d="M378.56,342.15c-11.2,1.29-21.2,6.91-34.38,4.02c17.38-13.12,29.62-28.02,35.34-49.86
c-22.86,11.18-44.29,22.27-69.86,17.87c29.22-14.58,53.47-34,65.19-66.51c3.09,2.11,5.44,3.31,7.29,5.04
c15.49,14.48,30.83,29.13,46.36,43.57c3.94,3.66,4.92,7.36,3.13,12.52c-12.8,37.05-17.33,75.43-17.57,114.4
c-0.11,17.53,0.54,35.07,0.78,52.6c0.02,1.77-0.35,3.55-0.66,6.4c-8.97,0-17.6,0-27.36,0c6.32-39.97,13.54-79.18,12.38-120.61
c-8.84,4.81-16.27,8.85-23.71,12.89c-0.49-0.48-0.97-0.96-1.46-1.44C378.33,363.41,381.6,353.68,378.56,342.15z"/>
</g>
<g>
<path class="st2" d="M207.81,179.57c3.71-5.83,8.78-8.93,15.2-8.75c5.91,0.17,10.65,3.14,13.82,8.68
c-3.37,5.93-8.7,7.74-14.45,7.81C216.53,187.39,211.48,185.04,207.81,179.57z"/>
</g>
<g>
<path class="st2" d="M277.66,179.72c3.23-6.12,7.85-9.04,14-9c6.15,0.04,10.67,3.08,13.58,8.58c-2.43,6.15-7.58,7.55-12.87,7.82
C286.5,187.42,281.29,185.46,277.66,179.72z"/>
</g>
<g>
<path class="st2" d="M194.81,240.77c0,0-0.08,0.08-0.08,0.08C194.72,240.85,194.81,240.77,194.81,240.77z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_scene">
<g>
<g>
<g>
<path class="st2" d="M141.31,362.45c10.55-10.81,21.11-21.61,32.39-33.17c-4.23-4.4-7.78-8.52-11.78-12.13
c-4.39-3.96-5.23-7.87-1.64-12.78c2.36-3.24,4.31-6.78,7.52-11.92c29.68,29.65,58.51,58.45,88.28,88.2
c29.63-29.58,58.38-58.28,88.43-88.27c3.76,6.48,7.17,11.44,9.48,16.88c0.68,1.6-1.26,4.92-2.82,6.75
c-3.78,4.43-8.04,8.45-12.61,13.15c3.87,4.06,7.01,7.46,10.26,10.75c6.02,6.1,12.2,12.04,18.09,18.27
c1.5,1.58,2.14,3.98,2.19,6.78c-11.12-2.35-15.32-13.36-25.7-18.87c-4.53,5.37-9.27,11-14.4,17.08
c4.03,8.46,15.77,12.55,18.84,22.89c-0.64,0.7-1.28,1.4-1.92,2.1c-2.18-1.32-4.7-2.29-6.49-4.01
c-7.5-7.21-14.75-14.68-22.17-21.99c-1.69-1.67-3.67-3.05-6.41-5.3c-5.41,5.88-10.51,11.42-16,17.4
c1.57,1.94,2.93,3.92,4.6,5.61c7.3,7.42,14.75,14.69,22,22.16c1.66,1.71,2.69,4.01,3.13,6.87
c-10.84-2.35-15.01-13.32-25.2-18.68c-4.93,5.38-10.02,10.94-15.43,16.85c4.67,9.02,15.38,13.49,19.26,23.07
c-0.54,0.67-1.09,1.34-1.63,2.01c-2.14-1.31-4.59-2.29-6.35-3.98c-7.49-7.22-14.75-14.69-22.17-21.99
c-1.69-1.66-3.68-3.01-5.89-4.79c-3.8,3-7.23,5.71-11.03,8.71c-3.77-2.97-7.19-5.68-11.01-8.69c-2.19,1.75-4.19,3.08-5.87,4.74
c-7.42,7.3-14.69,14.75-22.16,22c-1.73,1.67-4.02,2.76-6.91,3.23c2.31-10.77,13.12-15.02,18.63-25.24
c-5.42-4.76-11.09-9.74-17.21-15.11c-8.81,4.1-12.9,15.32-22.79,18.83c-0.62-0.47-1.25-0.95-1.87-1.42
c1.25-2.13,2.15-4.6,3.81-6.33c7.21-7.5,14.68-14.75,21.99-22.17c1.67-1.7,3.05-3.67,5.27-6.37
c-5.69-5.59-11.06-10.87-16.79-16.51c-2.48,2-4.47,3.36-6.16,5.02c-7.42,7.3-14.69,14.75-22.16,22c-1.71,1.66-4,2.72-6.87,3.19
c2.16-10.9,13.44-14.89,18.41-25.47c-5.23-4.81-10.76-9.89-16.39-15.06c-9.69,4.24-13.75,16.43-24.15,19.15
C143.03,364.74,142.17,363.6,141.31,362.45z"/>
</g>
<g>
<path class="st2" d="M441,403.48c-16.69-27.59-33.44-55.13-50.04-82.77c-42.46-70.68-84.85-141.39-127.26-212.1
c-1.34-2.23-2.47-4.58-4.3-8.02c13.34-3.15,24.63-8.77,32.97-20.46c1.71,2.53,2.89,3.85,3.6,5.4
c28.28,61.55,56.51,123.12,84.77,184.68c19.15,41.72,38.37,83.41,57.51,125.14c1.18,2.58,1.92,5.36,2.86,8.04L441,403.48z"/>
</g>
<g>
<path class="st2" d="M217.61,82.38c2.39,3.13,3.85,4.73,4.95,6.53c4.59,7.48,8.69,15.3,13.71,22.47
c4.35,6.21,4.12,11.18,0.16,17.73c-47.28,78.28-94.26,156.74-141.31,235.16c-6.51,10.85-13.01,21.71-19.54,32.55
c-1.13,1.88-2.39,3.68-4.72,4.92C119.57,295.76,168.27,189.77,217.61,82.38z"/>
</g>
<g>
<path class="st2" d="M477.25,255.92c-10.87-10.64-21.54-21.09-32.91-32.23c-5.58,5.75-10.68,11.01-16.24,16.75
c1.84,2.26,3.31,4.39,5.1,6.21c7.43,7.56,15,15,22.43,22.56c2.12,2.16,4.52,4.52-0.17,8.58c-7.22-6.76-14.48-13.55-21.88-20.47
c-6.08,5.51-11.66,10.57-17.97,16.3c7.88,8.42,14.65,15.65,21.42,22.88c-0.62,0.85-1.25,1.7-1.87,2.56
c-2.14-1.03-4.53-1.72-6.36-3.13c-13.8-10.59-21.18-25.52-27.46-41.16c-5.78-14.38-8.33-11.03,4.45-23.75
c7.23-7.19,14.4-14.44,21.65-21.61c1.71-1.69,3.62-3.17,5.84-5.08c1.73,1.12,3.41,1.86,4.63,3.06
c13.32,13.21,26.59,26.48,39.81,39.79C479.85,249.34,482.22,251.73,477.25,255.92z"/>
</g>
<g>
<path class="st2" d="M68.55,223.56c-12.92,10.59-22.16,23.11-34.32,32.22c-0.78-0.53-1.57-1.06-2.35-1.59
c0.43-1.85,0.25-4.3,1.39-5.46c14.33-14.51,28.84-28.83,43.34-43.18c0.39-0.38,1.12-0.42,1.97-0.71
c0.75,0.34,1.86,0.54,2.53,1.2c10.88,10.75,21.84,21.43,32.39,32.51c1.47,1.54,1.83,5.55,0.94,7.69
c-4.29,10.36-8.17,21.11-14.15,30.47c-5.16,8.08-12.9,14.53-19.62,21.58c-0.65,0.69-2.18,0.54-5.2,1.2
c3.65-11.71,15.03-15.79,20.22-26.77c-5.23-4.62-10.83-9.57-16.64-14.7c-9.41,4.67-13.78,15.49-23.35,19.4
c-0.67-0.54-1.35-1.07-2.02-1.61c1.11-1.99,1.87-4.32,3.4-5.91c7.07-7.35,14.38-14.47,21.55-21.72c1.84-1.86,3.48-3.92,6.4-7.23
C79.61,235.25,74.35,229.69,68.55,223.56z"/>
</g>
<g>
<path class="st2" d="M256.05,428.1c7.93,7.53,16.37,15.55,24.7,23.47c-8.21,8.27-16.4,16.51-24.37,24.54
c-8.23-7.98-16.67-16.16-25.11-24.34C239.8,443.62,248.21,435.58,256.05,428.1z"/>
</g>
<g>
<path class="st2" d="M254.88,73.27c6.48-5.93,12.68-11.6,18.52-16.94C275.4,65.47,265.2,75.93,254.88,73.27z"/>
</g>
<g>
<path class="st2" d="M238.87,49.47c0.54-7.99,6.12-13.62,15.88-13.57c-4.81,4.98-9.61,9.96-14.42,14.93
C239.84,50.38,239.35,49.92,238.87,49.47z"/>
</g>
<g>
<polygon class="st2" points="441.11,403.38 441.22,403.67 441,403.48 "/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_item" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M86.57,379.95c0-48.58,0-96.33,0-143.79c5.64-2.82,112.01-3.19,119.52-0.33c0.25,2.68,0.79,5.83,0.8,8.98
c0.07,26.94,0.01,53.88,0.08,80.83c0.01,3.17,0.51,6.33,0.85,10.3c32.36,0,63.92,0,97.01,0c0-33.87,0-66.95,0-99.19
c6.41-3.36,112.58-3.86,119.48-1.35c2.55,5.28,2.8,137.43-0.09,144.56C312.19,379.95,199.8,379.95,86.57,379.95z"/>
</g>
<g>
<path class="st2" d="M351.95,96.52c0,37.52,0,74.24,0,111.87c-15.41,0-30.07,0-45.61,0c-0.81-5.04-1.56-9.72-2.59-16.15
c-31.78-0.12-63.35-0.24-95.41,0.16c-1.01,5.85-1.81,10.52-2.76,16c-15.49,0-30.54,0-46.27,0c-0.48-3.17-1.18-5.7-1.19-8.24
c-0.08-31.43-0.09-62.85-0.03-94.28c0.02-8.73,1.64-10.33,10.48-10.33c58.36-0.05,116.72-0.03,175.09,0.01
C346.04,95.56,348.42,96.09,351.95,96.52z"/>
</g>
<g>
<path class="st2" d="M132.51,208.42c-9.52,0-18.03,0-27.47,0c0-37.52,0-74.16,0-111.86c9.22,0,17.87,0,27.47,0
C132.51,133.9,132.51,170.54,132.51,208.42z"/>
</g>
<g>
<path class="st2" d="M378.57,96.39c10.31,0,18.82,0,29.12,0c0.27,37.43,0.14,74.07,0.08,111.82c-10.01,0-18.66,0-29.13,0
C378.39,170.99,378.51,134.35,378.57,96.39z"/>
</g>
<g>
<path class="st2" d="M107.03,407.31c99.7,0,198.42,0,297.14,0c0.31,0.74,0.62,1.47,0.93,2.21c-3.8,2.18-7.48,4.61-11.44,6.42
c-1.72,0.78-4.02,0.36-6.06,0.36c-87.72,0.01-175.44-0.01-263.17,0.06C117.35,416.37,111.13,415.25,107.03,407.31z"/>
</g>
<g>
<path class="st2" d="M280.03,311.38c-16.62,0-31.68,0-47.61,0c0-31.35,0-61.94,0-93.7c15.6-1.68,30.82-0.85,47.53-0.45
C280.76,248.97,280.56,279.53,280.03,311.38z M267.36,293.14c0.39-3.77,0.85-6.35,0.89-8.94c0.12-7.13-0.2-14.28,0.21-21.39
c0.17-2.85,1.14-6.13,2.88-8.31c8.15-10.27,8.56-19.5,0.67-27.25c-8.45-8.3-21.51-8.87-30.61-1.33
c-8.41,6.98-10.24,17.21-3.09,25.35c4.73,5.38,5.6,10.91,5.4,17.36c-0.17,5.7-0.14,11.42,0.05,17.12
c0.08,2.32,0.82,4.63,1.34,7.39C252.64,293.14,259.56,293.14,267.36,293.14z"/>
</g>
<g>
<path class="st2" d="M459.64,208.46c-9.05,0-17.17,0-26.05,0c-0.44-3.46-1.09-6.2-1.09-8.93c-0.07-31.16-0.05-62.33-0.04-93.49
c0-1.22,0.07-2.44,0.15-3.66c0.3-4.41,2.7-6.57,7.1-6.7c4.5-0.13,6.66,2.09,7.24,6.46c4.34,32.91,8.76,65.81,13.07,98.73
C460.3,202.98,459.83,205.2,459.64,208.46z"/>
</g>
<g>
<path class="st2" d="M77.56,97.23c0,36.74,0,73.41,0,111.08c-8.48,0-16.35,0-25.02,0c-0.25-2.71-0.9-5.08-0.6-7.34
c4.21-32.52,8.49-65.04,12.9-97.53C65.84,96.02,68.83,94.5,77.56,97.23z"/>
</g>
<g>
<path class="st2" d="M451.71,362.72c0-42.84,0-84.74,0-127.72c3.45-0.21,6.42-0.39,10.08-0.61c0.46,3.5,1.09,6.04,1.1,8.58
c0.06,34.46-0.08,68.92,0.12,103.38C463.06,354.24,458.99,358.62,451.71,362.72z"/>
</g>
<g>
<path class="st2" d="M50.26,234.87c2.86,0,5.32,0,7.56,0c2.47,5.02,3.24,118.46,0.9,126.79c-5.37-3.13-9.67-6.58-9.66-13.41
c0.02-35.65-0.01-71.31,0.05-106.96C49.12,239.34,49.79,237.4,50.26,234.87z"/>
</g>
<g>
<path class="st2" d="M51.56,390.71c7.99,7.72,15.99,15.44,25.01,24.15c-9.12,2.16-16.82,2.02-24.49,0.42
c-1.03-0.21-2.41-2.03-2.45-3.14c-0.23-6.78-0.11-13.57-0.11-20.36C50.2,391.43,50.88,391.07,51.56,390.71z"/>
</g>
<g>
<path class="st2" d="M436.46,413.79c8.05-7.65,16.1-15.3,24.15-22.95c0.61,0.34,1.23,0.69,1.84,1.03
c0,6.76,0.19,13.52-0.17,20.26c-0.07,1.29-2.24,3.46-3.53,3.53c-7.16,0.35-14.35,0.17-21.53,0.17
C436.96,415.15,436.71,414.47,436.46,413.79z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_fight" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M98.54,121.71c7.19,0.33,14.38,0.67,22.81,1.06c1.18-7.93,2.28-15.34,3.38-22.75
c0.65-0.23,1.3-0.46,1.95-0.69c70.17,84.04,140.34,168.07,211.57,253.38c-9.84,8.24-18.85,15.78-28.82,24.13
C238.18,291.6,167.84,207.47,97.5,123.34C97.85,122.8,98.2,122.26,98.54,121.71z"/>
</g>
<g>
<path class="st2" d="M74.25,462.04c-10.75-7.58-20.15-14.21-30.69-21.64C87.39,378.65,130.68,317.64,175,255.19
c8.95,10.7,16.69,19.95,24.95,29.82C158.02,344.06,116.54,402.48,74.25,462.04z"/>
</g>
<g>
<path class="st2" d="M425.22,103.01c0.37,2.17,1.08,4.12,0.96,6.02c-1.52,23.89-10.41,44.55-26.71,62.21
c-17.85,19.34-40.04,31.93-63.81,42.21c-1.98,0.86-4.11,1.36-7.64,2.49c1.24-4.12,1.91-6.97,2.94-9.69
c6.52-17.26,11.93-34.75,11.33-53.5c-0.09-2.84-0.01-5.86-0.93-8.47c-2.37-6.7,0.06-11.13,5.24-15.36
c8.52-6.96,16.52-14.54,24.94-21.63c1.91-1.61,4.59-3.05,6.99-3.2c14.23-0.85,28.48-1.32,42.72-1.86
C422.24,102.2,423.23,102.61,425.22,103.01z"/>
</g>
<g>
<path class="st2" d="M291.85,453.14c-4.87-5.91-8.93-10.84-14.08-17.09c41.71-34.89,82.71-69.18,124.58-104.2
c4.79,5.78,8.96,10.8,14.01,16.89C374.53,383.82,333.55,418.17,291.85,453.14z"/>
</g>
<g>
<path class="st2" d="M273.79,115.61c10.76,7.57,20.25,14.24,30.73,21.61c-17.52,24.77-34.23,48.41-51.86,73.34
c-8.76-10.27-16.69-19.55-25.21-29.54C242.84,159.29,257.83,138.14,273.79,115.61z"/>
</g>
<g>
<path class="st2" d="M310.02,250.99c3.13-1.7,6.08-3.97,9.41-5.02c21.89-6.92,42.92-15.68,62.36-28.02
c29.04-18.43,51.93-42.06,63.17-75.38c4.67-13.85,6.52-28.16,6.18-42.77c-0.05-2.01-0.01-4.02-0.01-6.78
c3.9-2.17,7.86-4.37,12.69-7.05c1.31,3.33,2.56,5.61,3.12,8.05c3.1,13.52,1.31,26.78-2.57,39.85
c-16.18,54.48-81.45,113.08-140.32,120.1c-4.27,0.51-8.65,0.07-12.98,0.07C310.71,253.03,310.37,252.01,310.02,250.99z"/>
</g>
<g>
<path class="st2" d="M389.79,472.78c-11.28-13.51-21.9-26.23-33.01-39.54c8.13-9.93,17.68-16.81,28.3-24.44
c11.08,13.21,21.71,25.89,33.02,39.37C409.83,457.64,400.05,464.37,389.79,472.78z"/>
</g>
<g>
<path class="st2" d="M321.15,118.13c-11.98-8.39-23.18-16.22-35.16-24.61c4.46-12.23,8.63-23.66,13.37-36.67
c17.45,12.36,33.25,23.54,50.46,35.73C339.82,101.49,330.87,109.47,321.15,118.13z"/>
</g>
<g>
<path class="st2" d="M98.58,95.77c-7.12-0.81-13.28-1.35-19.35-2.36c-1.23-0.2-2.8-2.02-3.15-3.37
c-2.23-8.67-4.18-17.41-6.14-26.14c-0.15-0.68,0.35-1.51,0.74-2.98c1.89,0.47,3.64,0.68,5.2,1.33
c6.2,2.59,12.29,5.47,18.53,7.94c4.9,1.94,7.04,5.25,6.33,10.43C100.13,85.01,99.49,89.39,98.58,95.77z"/>
</g>
<g>
<path class="st2" d="M263.6,72.75c-4.58-8.72-9.17-17.44-14.34-27.29c9.64-1.5,17.2,0.6,26.32,3.04
c-3.26,8.72-6.26,16.73-9.26,24.75C265.41,73.08,264.5,72.92,263.6,72.75z"/>
</g>
<g>
<path class="st2" d="M328.1,39.22c10.42,7.7,21.69,12.69,29.96,23.17C349.73,64.21,326.41,46.59,328.1,39.22z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_compendium" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M172.73,49.37c21.98,0,43.98,0,66.87,0c0,137.52,0,274.28,0,412.73c-22.56,0.64-44.71,0.55-66.23,0.05
C170.22,455.66,169.78,57.56,172.73,49.37z M200.52,429.88c3.18-7.29,2.79-312.57-0.29-318.12c-6.66,0-13.58,0-20.13,0
c-3.18,7.31-2.79,312.56,0.29,318.12C187.06,429.88,193.98,429.88,200.52,429.88z M210.72,299.22
c-3.15,7.38-2.74,125.16,0.33,130.65c6.67,0,13.59,0,21.35,0c0-43.84,0-86.81,0-130.65
C224.64,299.22,217.72,299.22,210.72,299.22z"/>
</g>
<g>
<path class="st2" d="M145.38,142.76c0,85.62,0,170.31,0,256.67c-17.42,1.03-34.25,0.66-51.8,0.12
c-0.49-3.88-1.14-6.62-1.14-9.36c-0.05-79.17-0.06-158.34-0.03-237.52c0-9.54,1.47-10.94,11.07-11
c11.02-0.07,22.04-0.07,33.06,0.03C139.11,141.74,141.67,142.3,145.38,142.76z"/>
</g>
<g>
<path class="st2" d="M363.52,456.03c-12.7,2.35-23.74,4.39-35.68,6.6c-1.26-4.11-2.57-7.24-3.16-10.5
c-10.85-60.07-21.6-120.15-32.38-180.23c-7.75-43.2-15.53-86.4-23.26-129.6c-0.49-2.72-0.59-5.51-1-9.55
c12.13-2.2,23.57-4.27,36.31-6.58C324.11,236.33,343.65,345.24,363.52,456.03z"/>
</g>
<g>
<path class="st2" d="M30.77,95.93c12.29,0,23.52,0,35.63,0c0.49,3.12,1.29,5.83,1.29,8.53c0.07,53.47,0.07,106.95,0.02,160.42
c0,2.37-0.57,4.75-0.98,8c-11.97,0-23.53,0-35.96,0C30.77,213.88,30.77,155.54,30.77,95.93z"/>
</g>
<g>
<path class="st2" d="M367.58,238.23c7-3.03,12.81-5.54,20.08-8.69c31.66,74.22,62.88,147.39,94.52,221.55
c-7.17,3.14-12.98,5.68-20.06,8.77C430.48,385.69,399.26,312.48,367.58,238.23z"/>
</g>
<g>
<path class="st2" d="M65.98,461.62c-11.43,0-22.81,0-35.96,0c-0.23-38.48-0.1-76.1-0.08-114.56c13.02,0,24.42,0,35.56,0
C68.27,352.44,68.8,453.4,65.98,461.62z"/>
</g>
<g>
<path class="st2" d="M145.31,461.62c-17.64,0-34.34,0-51.98,0c0-12.22,0-23.59,0-34.65c5.83-2.99,44.82-3.3,51.98-0.36
C145.31,437.66,145.31,449.07,145.31,461.62z"/>
</g>
<g>
<path class="st2" d="M66.94,299.04c0,7.68,0,14,0,20c-5.68,3.23-28.48,3.6-36.48,0.32c0-5.15-0.23-10.92,0.17-16.64
c0.09-1.3,2.32-3.48,3.61-3.52C44.72,298.91,55.21,299.04,66.94,299.04z"/>
</g>
<g>
<path class="st2" d="M344.77,183.51c1.37-6.24,13.25-11.41,18.86-8.56C361.93,179.91,351.56,184.78,344.77,183.51z"/>
</g>
<g>
<path class="st2" d="M376.69,203.79c-1.47,1.58-2.66,3.99-4.46,4.57c-4.85,1.58-9.26,6.71-16.33,2.77
c5.69-6.11,12.27-7.7,18.8-9.41C375.37,202.41,376.03,203.1,376.69,203.79z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_settings" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M167.35,468.66c-13.39-1.77-50.61-24-55.69-33.14c1.08-1.73,2.27-3.8,3.62-5.75
c9.08-13.11,15.46-27.19,17.17-43.32c2.08-19.66-8.6-38.21-26.93-45.65c-18.45-7.49-36.8-5.28-55.13,0.52
c-2.27,0.72-4.61,1.24-7.95,2.13c-8.74-20.07-13.97-40.42-16.04-62.21c3.72-1,6.27-1.51,8.71-2.36
c10.15-3.55,20.93-5.98,30.28-11.03c32.02-17.29,37.2-51.45,11.57-77.58c-7.69-7.84-18.02-13.11-27.21-19.46
c-1.8-1.24-3.88-2.08-6.88-3.65c7.46-20.81,19.04-38.63,32.65-56.07c2.6,1.58,4.49,2.63,6.28,3.83
c12.84,8.66,26.44,15.16,42.16,16.87c27.62,3.01,49.81-16.05,50.75-43.89c0.44-12.98-0.7-25.69-5.26-37.95
c-0.57-1.52-0.94-3.13-1.27-4.72c-0.16-0.77-0.03-1.6-0.03-3.56c19.48-9.06,40.19-13.46,62.14-15.74
c1.02,3.75,1.82,6.21,2.34,8.72c3.47,16.64,9.06,32.26,21.51,44.52c15.73,15.49,38.24,17.59,56.71,5.52
c12.09-7.9,21.07-18.51,27.72-31.22c1.77-3.4,3.56-6.79,5.82-11.11c21.09,7.8,39.67,18.42,56.8,32.93
c-1.64,2.8-2.68,4.95-4.05,6.86C388.21,94.64,382,108.15,380,123.56c-3.04,23.55,11.24,44.26,34.61,49.71
c15.81,3.69,31.2,1.62,46.42-3.22c2.48-0.79,5-1.42,8.46-2.39c8.98,19.98,13.9,40.42,16.18,62.37c-3.8,0.94-6.46,1.76-9.18,2.25
c-16.65,3.01-31.7,9.36-43.86,21.42c-17.55,17.41-17.87,44.76-1.08,62.94c9.09,9.85,19.19,18.29,31.47,23.91
c1.97,0.9,3.73,2.29,6.35,3.94c-7.98,20.35-18.77,38.4-32.84,55.12c-3.06-1.75-5.24-2.79-7.18-4.15
c-11.9-8.34-24.87-13.72-39.36-15.81c-25.9-3.73-48.07,12.39-52.41,38.17c-2.51,14.96-0.26,29.24,4.49,43.36
c0.89,2.64,1.57,5.34,2.63,8.96c-20.39,9.22-41.13,13.92-63.52,15.93c-1.27-5.66-2.36-10.56-3.47-15.47
c-2.68-11.93-7.48-22.97-15.18-32.45c-19.22-23.66-48.23-25.35-70.63-3.31c-8,7.87-13.67,18.12-20.35,27.33
C170.02,464.25,168.74,466.5,167.35,468.66z M255.86,400.9c76.17,1.14,145.09-60.6,145.17-144.58
c0.07-81.43-64.18-146.3-147.02-145.43c-80.82,0.84-143.17,67.24-143.11,145.2C110.95,336.29,175.57,400.89,255.86,400.9z"/>
</g>
<g>
<path class="st2" d="M255.9,375.07c-66.32-0.01-119.05-52.79-119.18-119.01c-0.12-60.41,46.51-119.03,119.17-119.37
c66.88-0.31,119,51.98,119.5,119.66C375.87,322.28,322.28,375.08,255.9,375.07z M256.32,367.82
c61.81,0.01,112.28-50.05,111.82-111.65c-0.45-60.76-47.78-111.81-111.76-112.13c-63.11-0.31-112.37,51.07-112.41,112.06
C143.95,318.19,193.87,367.82,256.32,367.82z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_journal" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M448.42,92.12c-17.01,7.17-36.38,3.32-52.81,13.34c13.35,7.59,25.04,14.25,36.73,20.9
c-0.07,0.7-0.15,1.39-0.22,2.09c-10.32,2.08-20.63,4.16-30.95,6.23c-0.13,0.63-0.27,1.25-0.4,1.88
c14.07,8.7,28.14,17.4,42.66,26.38c-0.79,3.42-1.29,6.39-2.17,9.24c-9.51,30.75-25.84,57.54-47.17,81.49
c-28.41,31.88-43.98,69.29-47.66,111.76c-0.21,2.39-0.8,4.75-1.37,8.08c-3.69,0.38-7.21,1.06-10.74,1.07
c-52.87,0.07-105.74-0.15-158.6,0.15c-23.87,0.13-41.44,11.18-51.15,33.28c-13.04,29.65,8.96,66.89,45.53,62.06
c6.73-0.89,13.59-0.76,20.39-1.1c0.18,0.69,0.36,1.39,0.54,2.08c-1.95,1.11-3.78,2.8-5.87,3.23
c-13.93,2.87-27.83,6.21-41.92,7.89c-9.63,1.15-19.71,0.93-29.3-0.54c-25.73-3.96-39.5-20.96-46.09-44.94
c-7.68-27.98-4.86-55.9,1.11-83.65c2.48-11.54,6.41-22.77,9.52-34.19c1.48-5.44,4.92-7.99,10.38-8.84
c14.32-2.22,28.6-4.7,42.88-7.15c2.31-0.4,4.55-1.17,8.35-2.18c-12.43-12.92-23.92-24.85-35.68-37.07
c10.82-18.72,21.31-36.6,31.53-54.63c10.13-17.88,18.72-36.44,25.46-57.28c-4.1-0.52-6.79-1.1-9.48-1.17
c-19.98-0.48-39.99-0.43-59.95-1.38c-24.37-1.15-41.44-13.86-51.3-35.78c-9.41-20.93-7.08-40.88,7.01-59.34
c19.06-24.97,49.5-32.54,79.33-22.79c21.47,7.01,43.03,8.54,65.03,9.07c24.68,0.59,49.38,1.73,74.03,1.02
c37.08-1.07,74.08-3.17,111.05-7.28c35.35-3.93,63.98,16.8,71.28,52.84C448.69,88.4,448.42,90.05,448.42,92.12z M159.2,70.78
c0-1.99,0.18-2.66-0.04-3.16c-0.48-1.12-1.19-2.13-1.74-3.22c-6.25-12.36-16.75-18.76-29.81-22.21
c-18.28-4.83-36.2-6.22-53.53,3.12c-21.82,11.76-31.94,33.41-26.21,55.84c5.97,23.41,24.48,37.29,49.57,37.18
c17.77-0.08,24.02-8.04,17.19-24.49c-5.04-12.13-12.63-23.2-19.09-34.74c-1.22-2.18-2.46-4.34-4.73-8.33
C114.8,70.78,137.01,70.78,159.2,70.78z M125.86,137.58c1.23,0.84,1.72,1.47,2.22,1.47c10.98,0.11,21.98,0.38,32.94-0.05
c1.75-0.07,4.42-3.12,4.9-5.2c3.31-14.42,3.93-28.99,1.39-43.67c-1-5.82-3.9-8.4-9.91-8.3c-12.83,0.22-25.67,0.01-38.51,0.11
c-2.02,0.02-4.04,0.76-6.94,1.34C121.1,101.11,132.77,117.32,125.86,137.58z"/>
</g>
<g>
<path class="st2" d="M437.3,403.69c-12.05,6.13-24.1,12.27-36.16,18.4c0.06,0.71,0.11,1.41,0.17,2.12
c24.23,2.92,48.45,5.83,72.88,8.77c0.85,2.39,1.74,4.21,2.15,6.14c4.1,19.37-9.24,40.07-28.6,44.05
c-5.16,1.06-10.51,1.63-15.78,1.64c-68.14,0.11-136.27,0.08-204.41,0.06c-2.4,0-4.79-0.23-9.27-0.46
c10.87-12.42,17.06-25.54,17.43-40.56c0.37-14.77-2.14-29.17-10.26-43.31c3.8-0.56,6.28-1.23,8.77-1.24
c60.59-0.06,121.18-0.1,181.76,0.05c7,0.02,13.99,1.22,20.99,1.88C437.07,402.06,437.18,402.88,437.3,403.69z"/>
</g>
<g>
<path class="st2" d="M208.78,442.37c-2.84,0.3-5.59,0.73-8.35,0.86c-11.77,0.56-23.55,0.9-35.32,1.59
c-11.74,0.69-20.7-11.09-17.7-23.56c2.84-11.78,14.12-20.41,27.04-20.71C193.39,400.09,213.19,416.86,208.78,442.37z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_music" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M261.65,225.6c0.7,2.64,1.55,5.26,2.07,7.94c1.62,8.25,2.65,8.79,11.01,8.46c15-0.58,29.14,2.2,41.74,11.16
c14.6,10.37,19.64,25.5,21.71,42.14c2.78,22.32-10.19,36.76-25.52,49.9c-0.44,0.37-1.09,0.54-1.67,0.69
c-0.37,0.09-0.8-0.03-1.59-0.08c-3.15-4.92-2.8-9.59,0.96-14.33c6.14-7.74,11.54-15.89,12.05-26.24
c1.24-25.02-14.28-44.09-39.26-47.94c-4.59-0.71-9.31-0.53-15-0.81c0.44,4.72,0.51,7.73,1.03,10.66
c8.8,49.42,17.66,98.83,26.47,148.26c1.07,6.03,2.01,12.08,2.81,18.15c1.93,14.59-2.85,26.51-14.6,35.46
c-18.51,14.1-39.18,15.5-60.44,8.72c-16.02-5.1-25.76-22.74-22.74-38.34c3.49-18.02,17.24-29.36,35.42-29.2
c17.96,0.16,31.41,11.98,34.49,30.27c0.42,2.52,1.01,5.02,1.49,7.33c10.2,0.4,17.08-7.88,15.5-18.5
c-3.27-22-6.51-44.01-10.45-65.89c-5.72-31.73-12.04-63.35-18.15-95.01c-0.4-2.07-1.27-4.05-2.29-7.23
c-7.24,4.84-12.49,9.93-15.47,17.08c-5.54,13.32-3.63,26.35,1.74,39.25c1.25,3.01,1.98,6.23,2.95,9.35
c-0.69,0.48-1.39,0.96-2.08,1.44c-1.98-1.63-4.28-2.98-5.89-4.92c-14.99-18.11-14.14-48.78,1.75-66.18
c2.06-2.26,4.06-4.69,6.52-6.45c5.79-4.17,9.56-8.69,8.28-16.73c-0.43-2.71,3.11-6.04,4.83-9.09
C260.1,225.14,260.88,225.37,261.65,225.6z"/>
</g>
<g>
<path class="st2" d="M242.98,129.77c-0.54-2.18-1.24-3.66-1.24-5.15c0.06-27.65,5.24-53.97,20.63-77.55
c0.78-1.19,1.62-2.36,2.52-3.47c15.38-18.96,34.82-17.62,45.72,4.2c15.14,30.31,13.51,60.55-6.91,87.73
c-13.67,18.2-29.81,34.59-45.42,51.26c-18.14,19.38-36.83,38.27-50.39,61.34c-4.74,8.07-9.5,16.33-12.73,25.07
c-8.46,22.81-4.26,43.77,11.57,62.22c9.81,11.44,22.06,19.31,36.6,23.44c5.39,1.53,7.9,4.61,6.35,11.29
c-2.86,0-5.84,0.44-8.66-0.07c-31-5.57-50.06-25.12-60.87-53.46c-11.63-30.51-8.06-59.85,11.23-86
c15.34-20.81,32.18-40.57,49.3-59.97c15.92-18.03,33.27-34.79,49.64-52.44c11.16-12.03,12.87-27,10.85-42.48
c-1.06-8.1-5.98-13.73-14.13-16.01c-7.39-2.07-12.75,1.54-17.1,6.79c-2.57,3.1-5.27,6.57-6.35,10.32
c-3.64,12.7-7.02,25.51-9.61,38.46C252.62,122.04,249,126,242.98,129.77z"/>
</g>
</g>
</g>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><defs><radialGradient id="lorc-treasure-map-gradient-2"><stop offset="0%" stop-color="#b8e986" stop-opacity="1"></stop><stop offset="100%" stop-color="#ffe0af" stop-opacity="1"></stop></radialGradient><linearGradient x1="0" x2="0" y1="0" y2="1" id="lorc-treasure-map-gradient-5"><stop offset="0%" stop-color="#417505" stop-opacity="1"></stop><stop offset="100%" stop-color="#8b572a" stop-opacity="1"></stop></linearGradient></defs><g class="" transform="translate(1,0)" style=""><path d="M227.4 34.7c-10.1 0-20.2.2-30.2.5l6.1 65.6-61.1-62.5c-31.3 2.5-62.5 6.6-93.8 12.5l34.2 28.4-48-.6c35.1 100.2 6.9 182.6-.3 292.1L130 476.5c10-1.3 19.9-2.4 29.6-3.3l21.5-42.2 18.6 28.8 41.5-33.5.8 43c82.9-.2 157.7 9.1 235.7 7.9-28.2-73-31.2-143.6-31.9-209.2l-33.3-19.1 32.7-33.9c-.4-21.3-1.3-42-3.6-61.9l-57.4.7 50.2-41.7c-3.8-15.5-9-30.4-16.1-44.7l-29.5-23.9C335 38 281.2 34.6 227.4 34.7zm58.7 37c10.6 24.75 21.1 49.5 31.7 74.3 7.5-10.5 14.9-21 22.4-31.5 16 27.2 32 54.3 48 81.5l-16.2 9.5-33.3-56.7-42.5 59.4-15.2-10.9 24-33.5-21.9-51.5-24.6 40.1 12 22.6-16.5 8.8-18.3-34.5-24.8 58.2-17.2-7.4 32.5-76.2 7.7-18c4.8 9.2 9.6 18.3 14.5 27.4 12.5-20.6 25.1-41.11 37.7-61.6zM91.2 128c6.72 1.6 13.4 3.4 19.2 5.3-2.1 5.9-4.1 11.8-6.2 17.6-5.79-1.6-11.72-3.4-16.9-4.7 1.39-6 2.62-12.1 3.9-18.2zm37.9 13.4c6.3 3.8 12 7.2 17 12.8L132.6 167c-4-3.7-8.6-7-12.8-9.4zm28.7 32.3c2.1 7.4 2.1 15.7 1.6 22.5l-18.5-2.4c.1-5.1.3-10-1-14.5zm-21.2 35.7 17.2 7.1c-3.3 6.6-5.1 12.7-8.6 17.8l-16.3-9c2.6-5.4 5.6-10.8 7.7-15.9zm-16.5 34.1 17.7 6.1c-1.5 5.4-3 11.2-3.6 16.2l-18.6-2c1.3-7.5 2.1-14 4.5-20.3zm207.8 17.4c8.5 1 14.6 3 21.7 7.1l-9.8 16c-4.1-2.8-9.4-3.8-13.5-4.5zm-21.2 1.5c1.1 6.1 2.5 12.2 3.9 18.3-5.9 1.3-11.7 3.3-16.5 5.1l-6.8-17.4c6.7-2.4 13.5-4.7 19.4-6zm-37.9 15.9 11 15.1c-5.6 4-11.8 7.8-16.8 10.6l-8.9-16.4c5.1-2.9 10.6-6.3 14.7-9.3zM135.3 281c1.5 4.7 4.2 9.2 6.9 12.1l-13.8 12.6c-5.5-5.7-9.5-13.5-11.2-20.1zm230.3 3.3c3.5 6.4 6.8 12.7 8.7 19.1l-17.8 5.6c-2-5.4-4.3-10.8-6.8-14.8zm-127.4 10.9 6.9 17.3c-6.4 2.7-12.9 4.8-18.6 6.5l-5-18c5.9-1.6 11.3-3.8 16.7-5.8zm-83.8 6.2c5.3 1.7 10.8 3.4 15.7 4.2-1.2 6.1-2 12.3-2.8 18.5-7-1-14.5-3.3-20.5-5.7zm50 3.5 2.8 18.5c-7.2 1.3-13.4 1.6-19.8 1.9l-.4-18.7c5.9-.2 11.6-.8 17.4-1.7zm174.5 18c1 6.4 1.6 12.9 2.2 19.3l-18.7 1.5c-.4-6-.9-11.9-2-17.8zm-67.6 30.8c18.9 3.5 44.9 16.2 68.9 33.9 7.4-9.9 14.4-20.4 21.3-31.1l30.1 12.9c-4.7 12.3-15 25.6-28.6 37.2 17 16.2 30.9 34.5 37 53-13.8-18.1-31.1-31.8-50.3-42.8-23.4 15.8-52.7 25.9-79.6 20.4 22.9-4.4 40.6-16.6 55.8-32.6-16.5-7.5-33.8-13.9-51.3-20.1z" fill="#fff" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -1,5 +1,109 @@
# 13.0
## 13.0.30 - Le pansement d'Illysis
- les soins d'un joueur à l'autre fonctionne de nouveau
- la fenêtre de jet de compétence s'ouvre avec la caractéristique et la difficulté par défaut
- on peut saisir des valeurs négatives au clavier en sélectionnant les conditions/difficultés
## 13.0.29 - Le tricorne d'Illysis
- gestion des attaques avec jets V2 depuis l'onglet de combat
- les jets de résistance en mode V2 fonctionnent sans sélection de compétence
- affichage de l'expérience correspondant aux sorts pour aider à la création
- affichage de l'équivallent d'expérience des caractéristiques
## 13.0.28 - La quadrature d'Illysis
- Les ajustements de portée sont calculés pour les attaques à distance
- L'appel au moral dans le tchat ne déplace plus les boutons d'appel à la chance
- Correction d'apparence V13
- la fenêtre de choix des status utilisés est affichée correctement
- la fenêtre d'astrologie MJ est affichée correctement
## 13.0.27 - Les lunettes d'Illysis
- Les heures ne sont plus affichées en doublon sur les messages
- Les conteneurs ouverts sont mis à jour si leur contenu change
- Le style des icones d'objets est homogénéisé
- Ajout d'icônes: coffre, tissu de soie, parchemin
- Amélioration des choix d'actions de combat
- le choix d'initiative limite les attaques disponibles
- les compétences sont triées dans l'ordre décroissant
## 13.0.26 - La ménagerie d'Illysis
- Correction: on peut de nouveau modifier les caractéristiques des créatures
## 13.0.24 - Le grand oubli d'Illysis
- ajout d'un bouton pour supprimer les anciens messages du tchat
- correction de messages d'erreur 'User ... lacks permission' / 'Active Effect ... does not exist'
- les joueurs peuvent affecter leurs enchantements aux objets enchantables de leur équipement
- correction des boutons pour lancer les maladresses
- utilisation des tables de compendium
- correction des droits pour mise à jour du message
- correction de la cuisine
- reprise de l'image de cuisine dans l'équipement
- prise en compte de la difficulté pour préparer la nourriture brute
## 13.0.23 - Le marché d'Illysis
- Améliorations
- lors de la consommation suite à un achat, les jets d'appréciation/éthylisme
sont faits par l'acheteur. Du coup, c'est lui qui lance le jet d'appréciation
(pour un service ou un plat de qualité), et ses dés sont utilisés avec dice-so-nice
- les créatures ont le statut Inconscient quand leur endurance est à 0
- Fenêtre de jets V2
- les soins de blessures sont correctement appliqués
- correction d'affichage jet sans compétence/avec compétence
- correction de la prise en compte des tactiques
- correction du filtrage des défenses selon l'attaque
- lorsque le mode de visibilité des jets général est changé, les fenêtres de jets suivent ce changement
## 13.0.22 - Les reflets d'Illysis
- Améliorations
- Changements d'icones pour les Acteurs et Scènes
- Corrections diverses
- l'encombrement total est affiché avec deux décimales
- le poids des monnaies est de nouveau décimal
- Erreurs de typographie diverses
- Mise en réserve de sort par le Gardien
- Fenêtre de jets V2
- utilisation pour les jets quelconques
- la fenêtre de jet pour les jets depuis un lien texte
- affichage des ajustements dans la fenêtre d'attaque avec arme à distance
- gestion des défenses contre les armes à distance
- pas de tactiques pour les attaques à distance
- attaque depuis l'onglet combat de la feuille de personnage, sans token sélectionné
- défense contre possession
- correction du mode "méditation" quand le haut-rêvant ne connait pas de méditation
- correction du mode "jeu" quand le personnage ne connait pas de jeux
- correction du mode "oeuvre" quand le personnage ne connait pas d'oeuvres
- Corrections liées à Foundry v12/v13
- Fix ajout de notes dans le journal par un joueur (/chrono, ou clic sur le libelé de l'heure dans l'horloge)
## 13.0.21 - La folie d'Illysis
- Jets d'appréciation et de moral
- concerne la danse, musique, chant, jeu, les oeuvres, la nourriture, les services
- gestion des compétences d'appréciation pour les oeuvres
- pas de jet de moral si la qualité n'est pas suffisante (inférieure au moral,
à la compétence, moral déjà gagné pour la même raison)
- jet d'appréciation avec en option la compétence et la qualité
- jet de moral très heureux (pour Spasme)
- les jets de moral sont liés à des "bon moments"
- la liste des bons moments passés par un acteur est remise à zéro à Château Dormant
- Fenêtre de jet v2
- les possessions sont maintenant gérées avec les fenêtres V2
- on peut choisir sa voie de draconic pour contrer une possession ou conjurer
- La zone de saisie dans les journaux est mieux adaptée
- Correction des bonus de caractéristiques des cyans
## 13.0.20 - L'immobilisme d'Illysis
- Centrage du logo de pause

View File

@@ -63,6 +63,11 @@
#sidebar {
font-family: "GoudyAcc";
}
.sheet header.sheet-header h1 input .chat-message,
.window-app .window-header .chat-message,
#sidebar .chat-message {
font-family: "CaslonAntique";
}
/* For title, sidebar character and scene */
.sheet nav.sheet-tabs,
.window-app input,
@@ -74,11 +79,12 @@ select,
font-family: "CaslonAntique";
/* For sheet parts; For nav and title */
}
:root {
body {
/* =================== 2. DEBUGGING HIGHLIGHTERS ============ */
/* =================== 3. some constants ============ */
--fieldset-background: url(/ui/parchment.jpg);
--rdd-color-text-primary: hsla(0, 0%, 4%, 0.9);
--color-text-primary: hsla(0, 0%, 4%, 0.9);
--rdd-input-background: hsla(0, 0%, 0%, 0.1);
--rdd-color-border-input: hsla(0, 0%, 0%, 0.2);
--rdd-bg-input: hsla(0, 0%, 100%, 0.1);
@@ -682,7 +688,7 @@ select,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat {
font-family: CaslonAntique;
display: grid;
grid-template-areas: "img header buttons" "img resume buttons" "details details details" "actions actions actions";
grid-template-areas: "img header buttons" "img resume buttons" "details details details" "description description description" "actions actions actions";
grid-template-columns: 3rem 1fr 1.4rem;
grid-template-rows: max-content max-content max-content max-content;
gap: 0 0.5rem;
@@ -738,6 +744,17 @@ select,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-actions a img {
margin-right: 0.5rem;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-description,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-description {
grid-area: description;
text-align: justify;
display: flex;
flex-direction: column;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-description div,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-description div {
display: block;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons {
grid-area: buttons;
@@ -876,7 +893,7 @@ select,
max-width: 1.4rem;
max-height: 1.4rem;
border: 1px;
background: center / contain no-repeat url("../../icons/templates/icone_parchement_vierge.webp");
background: center / contain no-repeat url("../icons/templates/icone_parchement_vierge.webp");
}
.system-foundryvtt-reve-de-dragon .sheet-header .header-compteurs {
width: calc(60% - 110px - 1rem);
@@ -1193,6 +1210,10 @@ select,
color: rgba(173, 36, 26, 0.9);
text-shadow: 1px 1px 4px #3c3c3c;
}
.system-foundryvtt-reve-de-dragon .rdd-dialog.status-effects li {
display: flex;
flex-direction: row;
}
.system-foundryvtt-reve-de-dragon .rdd-dialog-select img.select-img {
-webkit-box-flex: 0;
-ms-flex: 0 0 48px;
@@ -1388,12 +1409,22 @@ select,
margin-inline: 0.1rem;
margin-block: 0.1rem;
}
.system-foundryvtt-reve-de-dragon .prosemirror menu {
background-color: var(--color-background-chat-message);
}
.system-foundryvtt-reve-de-dragon .app.sheet fieldset :is(label, input) {
font-family: CaslonAntique;
text-align: justify;
font-size: 1rem;
letter-spacing: 1px;
}
.system-foundryvtt-reve-de-dragon .app.sheet input.attribute-value {
background-color: rgba(0, 0, 0, 0.05);
border: 1px solid var(--color-border-light-tertiary);
padding: 1px 3px;
height: var(--form-field-height);
border-radius: 3px;
}
.system-foundryvtt-reve-de-dragon .app.sheet div.form-group {
clear: both;
display: flex;
@@ -1402,19 +1433,22 @@ select,
margin: 0.1rem 0;
align-items: center;
}
.system-foundryvtt-reve-de-dragon .prosemirror menu {
background-color: var(--color-background-chat-message);
}
.system-foundryvtt-reve-de-dragon .app.sheet .editor.prosemirror {
height: fit-content;
min-height: 5rem;
min-height: 6rem;
}
.system-foundryvtt-reve-de-dragon .app.sheet .editor.prosemirror .editor-container {
min-height: 5rem;
height: 8rem;
min-height: 6rem;
height: calc(100% - 3rem);
margin: 0;
flex: none;
}
.system-foundryvtt-reve-de-dragon .app.sheet.journal-entry-page .editor.prosemirror {
height: 100%;
}
.system-foundryvtt-reve-de-dragon .app.sheet.journal-entry-page .editor.prosemirror .editor-container {
height: calc(100% - 6rem);
}
.system-foundryvtt-reve-de-dragon .large-editor {
border: 2;
height: fit-content;
@@ -1424,18 +1458,18 @@ select,
.system-foundryvtt-reve-de-dragon .editor {
border: 2;
height: fit-content;
min-height: 5rem;
min-height: 6rem;
padding: 0 3px;
}
.system-foundryvtt-reve-de-dragon .medium-editor {
border: 2;
min-height: 8rem;
min-height: 9rem;
padding: 0 3px;
align-items: top;
}
.system-foundryvtt-reve-de-dragon .small-editor {
border: 2;
min-height: 2rem;
min-height: 4rem;
padding: 0 3px;
}
.system-foundryvtt-reve-de-dragon .foundryvtt-reve-de-dragon.sheet :is(.large-editor, .editor, .medium-editor, .small-editor) {
@@ -1498,6 +1532,7 @@ select,
}
.system-foundryvtt-reve-de-dragon .item-actions-controls img,
.system-foundryvtt-reve-de-dragon .item-controls img {
vertical-align: text-bottom;
display: inline;
max-width: 1rem;
max-height: 1rem;
@@ -1510,10 +1545,17 @@ select,
font-size: 0.8em;
color: var(--color-controls-light);
}
.system-foundryvtt-reve-de-dragon .item-actions-controls img:hover,
.system-foundryvtt-reve-de-dragon .item-controls img:hover,
.system-foundryvtt-reve-de-dragon .item-actions-controls i:is(.fas, .far, .fa-solid, .fa-regular):hover,
.system-foundryvtt-reve-de-dragon .item-controls i:is(.fas, .far, .fa-solid, .fa-regular):hover {
.system-foundryvtt-reve-de-dragon .item-actions-controls a:hover,
.system-foundryvtt-reve-de-dragon .item-controls a:hover {
text-shadow: 1px 0px 0px #ff6600;
}
.system-foundryvtt-reve-de-dragon .item-actions-controls a img:hover,
.system-foundryvtt-reve-de-dragon .item-controls a img:hover {
opacity: 0.6;
filter: drop-shadow(1px 1px 1px #009966) invert(0.8);
}
.system-foundryvtt-reve-de-dragon .item-actions-controls a i:is(.fas, .far, .fa-solid, .fa-regular):hover,
.system-foundryvtt-reve-de-dragon .item-controls a i:is(.fas, .far, .fa-solid, .fa-regular):hover {
opacity: 0.6;
}
.system-foundryvtt-reve-de-dragon .rdd-roll-dialog .description-sort {
@@ -1696,25 +1738,121 @@ select,
.system-foundryvtt-reve-de-dragon form.app-personnage-aleatoire h2 {
min-width: 30rem;
}
.system-foundryvtt-reve-de-dragon .app-calendar-astrologie div.theme-astral {
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.theme-astral {
width: 14rem;
margin: 0.4rem;
}
.system-foundryvtt-reve-de-dragon .app-calendar-astrologie div.horloge-roue {
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-roue {
position: relative;
left: calc(50% - 6.5rem);
width: 13rem;
height: 13rem;
}
.system-foundryvtt-reve-de-dragon .app-calendar-astrologie div.horloge-roue div.horloge-heure {
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-roue div.horloge-heure {
position: absolute;
width: 1.8rem;
height: 1.8rem;
}
.system-foundryvtt-reve-de-dragon .app-calendar-astrologie div.horloge-roue div.horloge-heure img.horloge-heure-img {
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-roue div.horloge-heure img.horloge-heure-img {
width: 2rem;
height: 2rem;
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-heure.heure-01 {
top: calc(50% - 1rem + 0 * 41%);
left: calc(50% - 1rem + -1 * 41%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-heure.heure-02 {
top: calc(50% - 1rem + -0.5 * 41%);
left: calc(50% - 1rem + -0.8660254 * 41%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-heure.heure-03 {
top: calc(50% - 1rem + -0.8660254 * 41%);
left: calc(50% - 1rem + -0.5 * 41%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-heure.heure-04 {
top: calc(50% - 1rem + -1 * 41%);
left: calc(50% - 1rem + 0 * 41%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-heure.heure-05 {
top: calc(50% - 1rem + -0.8660254 * 41%);
left: calc(50% - 1rem + 0.5 * 41%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-heure.heure-06 {
top: calc(50% - 1rem + -0.5 * 41%);
left: calc(50% - 1rem + 0.8660254 * 41%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-heure.heure-07 {
top: calc(50% - 1rem + 0 * 41%);
left: calc(50% - 1rem + 1 * 41%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-heure.heure-08 {
top: calc(50% - 1rem + 0.5 * 41%);
left: calc(50% - 1rem + 0.8660254 * 41%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-heure.heure-09 {
top: calc(50% - 1rem + 0.8660254 * 41%);
left: calc(50% - 1rem + 0.5 * 41%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-heure.heure-10 {
top: calc(50% - 1rem + 1 * 41%);
left: calc(50% - 1rem + 0 * 41%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-heure.heure-11 {
top: calc(50% - 1rem + 0.8660254 * 41%);
left: calc(50% - 1rem + -0.5 * 41%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-heure.heure-12 {
top: calc(50% - 1rem + 0.5 * 41%);
left: calc(50% - 1rem + -0.8660254 * 41%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-ajustement.heure-01 {
top: calc(50% - 0.4rem + 0 * 28%);
left: calc(50% - 0.4rem + -1 * 28%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-ajustement.heure-02 {
top: calc(50% - 0.4rem + -0.5 * 28%);
left: calc(50% - 0.4rem + -0.8660254 * 28%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-ajustement.heure-03 {
top: calc(50% - 0.4rem + -0.8660254 * 28%);
left: calc(50% - 0.4rem + -0.5 * 28%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-ajustement.heure-04 {
top: calc(50% - 0.4rem + -1 * 28%);
left: calc(50% - 0.4rem + 0 * 28%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-ajustement.heure-05 {
top: calc(50% - 0.4rem + -0.8660254 * 28%);
left: calc(50% - 0.4rem + 0.5 * 28%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-ajustement.heure-06 {
top: calc(50% - 0.4rem + -0.5 * 28%);
left: calc(50% - 0.4rem + 0.8660254 * 28%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-ajustement.heure-07 {
top: calc(50% - 0.4rem + 0 * 28%);
left: calc(50% - 0.4rem + 1 * 28%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-ajustement.heure-08 {
top: calc(50% - 0.4rem + 0.5 * 28%);
left: calc(50% - 0.4rem + 0.8660254 * 28%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-ajustement.heure-09 {
top: calc(50% - 0.4rem + 0.8660254 * 28%);
left: calc(50% - 0.4rem + 0.5 * 28%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-ajustement.heure-10 {
top: calc(50% - 0.4rem + 1 * 28%);
left: calc(50% - 0.4rem + 0 * 28%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-ajustement.heure-11 {
top: calc(50% - 0.4rem + 0.8660254 * 28%);
left: calc(50% - 0.4rem + -0.5 * 28%);
}
.system-foundryvtt-reve-de-dragon .rdd-calendar-astrologie div.horloge-ajustement.heure-12 {
top: calc(50% - 0.4rem + 0.5 * 28%);
left: calc(50% - 0.4rem + -0.8660254 * 28%);
}
.system-foundryvtt-reve-de-dragon .window-app .window-content,
.system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-body,
.system-foundryvtt-reve-de-dragon .application .window-content {
@@ -2559,102 +2697,6 @@ select,
top: calc(50% - 0.7rem + 0.5 * 38%);
left: calc(50% - 0.7rem + -0.8660254 * 41%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-heure.heure-01 {
top: calc(50% - 1rem + 0 * 41%);
left: calc(50% - 1rem + -1 * 41%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-heure.heure-02 {
top: calc(50% - 1rem + -0.5 * 41%);
left: calc(50% - 1rem + -0.8660254 * 41%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-heure.heure-03 {
top: calc(50% - 1rem + -0.8660254 * 41%);
left: calc(50% - 1rem + -0.5 * 41%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-heure.heure-04 {
top: calc(50% - 1rem + -1 * 41%);
left: calc(50% - 1rem + 0 * 41%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-heure.heure-05 {
top: calc(50% - 1rem + -0.8660254 * 41%);
left: calc(50% - 1rem + 0.5 * 41%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-heure.heure-06 {
top: calc(50% - 1rem + -0.5 * 41%);
left: calc(50% - 1rem + 0.8660254 * 41%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-heure.heure-07 {
top: calc(50% - 1rem + 0 * 41%);
left: calc(50% - 1rem + 1 * 41%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-heure.heure-08 {
top: calc(50% - 1rem + 0.5 * 41%);
left: calc(50% - 1rem + 0.8660254 * 41%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-heure.heure-09 {
top: calc(50% - 1rem + 0.8660254 * 41%);
left: calc(50% - 1rem + 0.5 * 41%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-heure.heure-10 {
top: calc(50% - 1rem + 1 * 41%);
left: calc(50% - 1rem + 0 * 41%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-heure.heure-11 {
top: calc(50% - 1rem + 0.8660254 * 41%);
left: calc(50% - 1rem + -0.5 * 41%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-heure.heure-12 {
top: calc(50% - 1rem + 0.5 * 41%);
left: calc(50% - 1rem + -0.8660254 * 41%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-ajustement.heure-01 {
top: calc(50% - 0.4rem + 0 * 28%);
left: calc(50% - 0.4rem + -1 * 28%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-ajustement.heure-02 {
top: calc(50% - 0.4rem + -0.5 * 28%);
left: calc(50% - 0.4rem + -0.8660254 * 28%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-ajustement.heure-03 {
top: calc(50% - 0.4rem + -0.8660254 * 28%);
left: calc(50% - 0.4rem + -0.5 * 28%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-ajustement.heure-04 {
top: calc(50% - 0.4rem + -1 * 28%);
left: calc(50% - 0.4rem + 0 * 28%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-ajustement.heure-05 {
top: calc(50% - 0.4rem + -0.8660254 * 28%);
left: calc(50% - 0.4rem + 0.5 * 28%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-ajustement.heure-06 {
top: calc(50% - 0.4rem + -0.5 * 28%);
left: calc(50% - 0.4rem + 0.8660254 * 28%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-ajustement.heure-07 {
top: calc(50% - 0.4rem + 0 * 28%);
left: calc(50% - 0.4rem + 1 * 28%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-ajustement.heure-08 {
top: calc(50% - 0.4rem + 0.5 * 28%);
left: calc(50% - 0.4rem + 0.8660254 * 28%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-ajustement.heure-09 {
top: calc(50% - 0.4rem + 0.8660254 * 28%);
left: calc(50% - 0.4rem + 0.5 * 28%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-ajustement.heure-10 {
top: calc(50% - 0.4rem + 1 * 28%);
left: calc(50% - 0.4rem + 0 * 28%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-ajustement.heure-11 {
top: calc(50% - 0.4rem + 0.8660254 * 28%);
left: calc(50% - 0.4rem + -0.5 * 28%);
}
.system-foundryvtt-reve-de-dragon .calendar-astrologie div.horloge-ajustement.heure-12 {
top: calc(50% - 0.4rem + 0.5 * 28%);
left: calc(50% - 0.4rem + -0.8660254 * 28%);
}
.system-foundryvtt-reve-de-dragon .calendar-boutons-heure .calendar-btn:is(.calendar-lyre, .calendar-vaisseau) img {
color: hsla(0, 0%, 100%, 0.5);
border: none;

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
icons/objets/coffre.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
icons/objets/parchemin.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

5
info-message.html Normal file
View File

@@ -0,0 +1,5 @@
<h3>Joyeuses fêtes</h3>
<p>
VincentVK, LeRatierBretonnien et toute l'équipe de Scriptrarium vous
souhaitent de joyeuses et oniriques fêtes !
</p>

View File

@@ -1,4 +1,4 @@
:root {
body {
/* =================== 2. DEBUGGING HIGHLIGHTERS ============ */
// --debug-background-color-red: #ff000054;
@@ -13,6 +13,7 @@
/* =================== 3. some constants ============ */
--fieldset-background: url(/ui/parchment.jpg);
--rdd-color-text-primary: hsla(0, 0%, 4%, 0.9);
--color-text-primary: hsla(0, 0%, 4%, 0.9);
--rdd-input-background:hsla(0, 0%, 0%, 0.1);
--rdd-color-border-input: hsla(0, 0%, 0%, 0.2);
--rdd-bg-input: hsla(0, 0%, 100%, 0.1);

View File

@@ -71,7 +71,11 @@
.sheet header.sheet-header h1 input,
.window-app .window-header,
#sidebar {
font-family: "GoudyAcc"
font-family: "GoudyAcc";
.chat-message{
font-family: "CaslonAntique";
}
}
/* For title, sidebar character and scene */

View File

@@ -136,7 +136,7 @@
max-height: 1.4rem;
border: 1px;
background: center / contain no-repeat
url("../../icons/templates/icone_parchement_vierge.webp");
url("../icons/templates/icone_parchement_vierge.webp");
}
.sheet-header .header-compteurs {
@@ -484,7 +484,10 @@
color: rgba(173, 36, 26, 0.9);
text-shadow: 1px 1px 4px rgba(60, 60, 60, 1);
}
.rdd-dialog.status-effects li {
display: flex;
flex-direction: row;
}
.rdd-dialog-select img.select-img {
-webkit-box-flex: 0;
-ms-flex: 0 0 48px;
@@ -689,6 +692,7 @@
}
}
}
fieldset {
border-style: groove;
border-width: 0.1rem;
@@ -697,36 +701,56 @@
margin-inline: 0.1rem;
margin-block: 0.1rem;
}
.app.sheet fieldset :is(label, input) {
font-family: CaslonAntique;
text-align: justify;
font-size: 1rem;
letter-spacing: 1px;
}
.app.sheet div.form-group {
clear: both;
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: 0.1rem 0;
align-items: center;
}
.prosemirror {
menu {
background-color: var(--color-background-chat-message);
}
}
.app.sheet .editor.prosemirror {
height: fit-content;
min-height: 5rem;
}
.app.sheet .editor.prosemirror .editor-container {
min-height: 5rem;
height: 8rem;
margin: 0;
flex: none;
.app.sheet{
fieldset :is(label, input) {
font-family: CaslonAntique;
text-align: justify;
font-size: 1rem;
letter-spacing: 1px;
}
input.attribute-value {
background-color: rgba(0, 0, 0, 0.05);
border: 1px solid var(--color-border-light-tertiary);
padding: 1px 3px;
height: var(--form-field-height);
border-radius: 3px;
}
div.form-group {
clear: both;
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: 0.1rem 0;
align-items: center;
}
.editor.prosemirror {
height: fit-content;
min-height: 6rem;
.editor-container {
min-height: 6rem;
height: calc(100% - 3rem);
margin: 0;
flex: none;
}
}
}
.app.sheet.journal-entry-page .editor.prosemirror{
height: 100%;
.editor-container {
height: calc(100% - 6rem);
}
}
.large-editor {
border: 2;
@@ -738,20 +762,20 @@
.editor {
border: 2;
height: fit-content;
min-height: 5rem;
min-height: 6rem;
padding: 0 3px;
}
.medium-editor {
border: 2;
min-height: 8rem;
min-height: 9rem;
padding: 0 3px;
align-items: top;
}
.small-editor {
border: 2;
min-height: 2rem;
min-height: 4rem;
padding: 0 3px;
}
@@ -831,6 +855,7 @@
// }
img {
vertical-align: text-bottom;
display: inline;
max-width: 1rem;
max-height: 1rem;
@@ -844,8 +869,16 @@
color: var(--color-controls-light);
}
img:hover,
i:is(.fas, .far, .fa-solid, .fa-regular):hover {
a:hover {
text-shadow: 1px 0px 0px #ff6600;
}
a img:hover{
opacity: 0.6;
filter: drop-shadow(1px 1px 1px #009966) invert(0.8);
}
a i:is(.fas, .far, .fa-solid, .fa-regular):hover {
opacity: 0.6;
}
}
@@ -1035,7 +1068,7 @@
min-width: 30rem;
}
}
.app-calendar-astrologie {
.rdd-calendar-astrologie {
div.theme-astral {
width: 14rem;
margin: 0.4rem;
@@ -1055,6 +1088,105 @@
}
}
}
div.horloge-heure.heure-01 {
top: calc(50% - 1rem + sin(-180deg) * 41%);
left: calc(50% - 1rem + cos(-180deg) * 41%);
}
div.horloge-heure.heure-02 {
top: calc(50% - 1rem + sin(-150deg) * 41%);
left: calc(50% - 1rem + cos(-150deg) * 41%);
}
div.horloge-heure.heure-03 {
top: calc(50% - 1rem + sin(-120deg) * 41%);
left: calc(50% - 1rem + cos(-120deg) * 41%);
}
div.horloge-heure.heure-04 {
top: calc(50% - 1rem + sin(-90deg) * 41%);
left: calc(50% - 1rem + cos(-90deg) * 41%);
}
div.horloge-heure.heure-05 {
top: calc(50% - 1rem + sin(-60deg) * 41%);
left: calc(50% - 1rem + cos(-60deg) * 41%);
}
div.horloge-heure.heure-06 {
top: calc(50% - 1rem + sin(-30deg) * 41%);
left: calc(50% - 1rem + cos(-30deg) * 41%);
}
div.horloge-heure.heure-07 {
top: calc(50% - 1rem + sin(-0deg) * 41%);
left: calc(50% - 1rem + cos(-0deg) * 41%);
}
div.horloge-heure.heure-08 {
top: calc(50% - 1rem + sin(30deg) * 41%);
left: calc(50% - 1rem + cos(30deg) * 41%);
}
div.horloge-heure.heure-09 {
top: calc(50% - 1rem + sin(60deg) * 41%);
left: calc(50% - 1rem + cos(60deg) * 41%);
}
div.horloge-heure.heure-10 {
top: calc(50% - 1rem + sin(90deg) * 41%);
left: calc(50% - 1rem + cos(90deg) * 41%);
}
div.horloge-heure.heure-11 {
top: calc(50% - 1rem + sin(120deg) * 41%);
left: calc(50% - 1rem + cos(120deg) * 41%);
}
div.horloge-heure.heure-12 {
top: calc(50% - 1rem + sin(150deg) * 41%);
left: calc(50% - 1rem + cos(150deg) * 41%);
}
div.horloge-ajustement.heure-01 {
top: calc(50% - 0.4rem + sin(180deg) * 28%);
left: calc(50% - 0.4rem + cos(180deg) * 28%);
}
div.horloge-ajustement.heure-02 {
top: calc(50% - 0.4rem + sin(-150deg) * 28%);
left: calc(50% - 0.4rem + cos(-150deg) * 28%);
}
div.horloge-ajustement.heure-03 {
top: calc(50% - 0.4rem + sin(-120deg) * 28%);
left: calc(50% - 0.4rem + cos(-120deg) * 28%);
}
div.horloge-ajustement.heure-04 {
top: calc(50% - 0.4rem + sin(-90deg) * 28%);
left: calc(50% - 0.4rem + cos(-90deg) * 28%);
}
div.horloge-ajustement.heure-05 {
top: calc(50% - 0.4rem + sin(-60deg) * 28%);
left: calc(50% - 0.4rem + cos(-60deg) * 28%);
}
div.horloge-ajustement.heure-06 {
top: calc(50% - 0.4rem + sin(-30deg) * 28%);
left: calc(50% - 0.4rem + cos(-30deg) * 28%);
}
div.horloge-ajustement.heure-07 {
top: calc(50% - 0.4rem + sin(0deg) * 28%);
left: calc(50% - 0.4rem + cos(0deg) * 28%);
}
div.horloge-ajustement.heure-08 {
top: calc(50% - 0.4rem + sin(30deg) * 28%);
left: calc(50% - 0.4rem + cos(30deg) * 28%);
}
div.horloge-ajustement.heure-09 {
top: calc(50% - 0.4rem + sin(60deg) * 28%);
left: calc(50% - 0.4rem + cos(60deg) * 28%);
}
div.horloge-ajustement.heure-10 {
top: calc(50% - 0.4rem + sin(90deg) * 28%);
left: calc(50% - 0.4rem + cos(90deg) * 28%);
}
div.horloge-ajustement.heure-11 {
top: calc(50% - 0.4rem + sin(120deg) * 28%);
left: calc(50% - 0.4rem + cos(120deg) * 28%);
}
div.horloge-ajustement.heure-12 {
top: calc(50% - 0.4rem + sin(150deg) * 28%);
left: calc(50% - 0.4rem + cos(150deg) * 28%);
}
}
.window-app .window-content,
@@ -1992,106 +2124,6 @@
}
}
.calendar-astrologie {
div.horloge-heure.heure-01 {
top: calc(50% - 1rem + sin(-180deg) * 41%);
left: calc(50% - 1rem + cos(-180deg) * 41%);
}
div.horloge-heure.heure-02 {
top: calc(50% - 1rem + sin(-150deg) * 41%);
left: calc(50% - 1rem + cos(-150deg) * 41%);
}
div.horloge-heure.heure-03 {
top: calc(50% - 1rem + sin(-120deg) * 41%);
left: calc(50% - 1rem + cos(-120deg) * 41%);
}
div.horloge-heure.heure-04 {
top: calc(50% - 1rem + sin(-90deg) * 41%);
left: calc(50% - 1rem + cos(-90deg) * 41%);
}
div.horloge-heure.heure-05 {
top: calc(50% - 1rem + sin(-60deg) * 41%);
left: calc(50% - 1rem + cos(-60deg) * 41%);
}
div.horloge-heure.heure-06 {
top: calc(50% - 1rem + sin(-30deg) * 41%);
left: calc(50% - 1rem + cos(-30deg) * 41%);
}
div.horloge-heure.heure-07 {
top: calc(50% - 1rem + sin(-0deg) * 41%);
left: calc(50% - 1rem + cos(-0deg) * 41%);
}
div.horloge-heure.heure-08 {
top: calc(50% - 1rem + sin(30deg) * 41%);
left: calc(50% - 1rem + cos(30deg) * 41%);
}
div.horloge-heure.heure-09 {
top: calc(50% - 1rem + sin(60deg) * 41%);
left: calc(50% - 1rem + cos(60deg) * 41%);
}
div.horloge-heure.heure-10 {
top: calc(50% - 1rem + sin(90deg) * 41%);
left: calc(50% - 1rem + cos(90deg) * 41%);
}
div.horloge-heure.heure-11 {
top: calc(50% - 1rem + sin(120deg) * 41%);
left: calc(50% - 1rem + cos(120deg) * 41%);
}
div.horloge-heure.heure-12 {
top: calc(50% - 1rem + sin(150deg) * 41%);
left: calc(50% - 1rem + cos(150deg) * 41%);
}
div.horloge-ajustement.heure-01 {
top: calc(50% - 0.4rem + sin(180deg) * 28%);
left: calc(50% - 0.4rem + cos(180deg) * 28%);
}
div.horloge-ajustement.heure-02 {
top: calc(50% - 0.4rem + sin(-150deg) * 28%);
left: calc(50% - 0.4rem + cos(-150deg) * 28%);
}
div.horloge-ajustement.heure-03 {
top: calc(50% - 0.4rem + sin(-120deg) * 28%);
left: calc(50% - 0.4rem + cos(-120deg) * 28%);
}
div.horloge-ajustement.heure-04 {
top: calc(50% - 0.4rem + sin(-90deg) * 28%);
left: calc(50% - 0.4rem + cos(-90deg) * 28%);
}
div.horloge-ajustement.heure-05 {
top: calc(50% - 0.4rem + sin(-60deg) * 28%);
left: calc(50% - 0.4rem + cos(-60deg) * 28%);
}
div.horloge-ajustement.heure-06 {
top: calc(50% - 0.4rem + sin(-30deg) * 28%);
left: calc(50% - 0.4rem + cos(-30deg) * 28%);
}
div.horloge-ajustement.heure-07 {
top: calc(50% - 0.4rem + sin(0deg) * 28%);
left: calc(50% - 0.4rem + cos(0deg) * 28%);
}
div.horloge-ajustement.heure-08 {
top: calc(50% - 0.4rem + sin(30deg) * 28%);
left: calc(50% - 0.4rem + cos(30deg) * 28%);
}
div.horloge-ajustement.heure-09 {
top: calc(50% - 0.4rem + sin(60deg) * 28%);
left: calc(50% - 0.4rem + cos(60deg) * 28%);
}
div.horloge-ajustement.heure-10 {
top: calc(50% - 0.4rem + sin(90deg) * 28%);
left: calc(50% - 0.4rem + cos(90deg) * 28%);
}
div.horloge-ajustement.heure-11 {
top: calc(50% - 0.4rem + sin(120deg) * 28%);
left: calc(50% - 0.4rem + cos(120deg) * 28%);
}
div.horloge-ajustement.heure-12 {
top: calc(50% - 0.4rem + sin(150deg) * 28%);
left: calc(50% - 0.4rem + cos(150deg) * 28%);
}
}
.calendar-boutons-heure {
.calendar-btn:is(.calendar-lyre, .calendar-vaisseau) img {
color: hsla(0, 0%, 100%, 0.5);

View File

@@ -6,7 +6,9 @@
"img header buttons"
"img resume buttons"
"details details details"
"actions actions actions";
"description description description"
"actions actions actions"
;
grid-template-columns: 3rem 1fr 1.4rem;
grid-template-rows: max-content max-content max-content max-content;
gap: 0 0.5rem;
@@ -53,6 +55,15 @@
}
}
}
div.chat-description {
grid-area: description;
text-align: justify;
display: flex;
flex-direction: column;
div {
display: block;
}
}
div.chat-buttons {
grid-area: buttons;

View File

@@ -40,17 +40,21 @@ export class ChatVente {
static async diminuerQuantiteAchatVente(chatMessageId, quantite) {
const chatMessage = game.messages.get(chatMessageId)
const vente = ChatVente.getDetailVente(chatMessageId)
vente.nbLots = Math.max(0, vente.nbLots - quantite)
await chatMessage.setFlag(SYSTEM_RDD, NB_LOTS, vente.nbLots)
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.hbs', vente);
chatMessage.update({ content: html });
chatMessage.render(true);
const vente = ChatVente.getDetailVente(chatMessageId)
if (vente.nbLots <= quantite) {
ChatUtility.removeChatMessageId(chatMessageIdVente);
}
else {
vente.nbLots = vente.nbLots - quantite
await chatMessage.setFlag(SYSTEM_RDD, NB_LOTS, vente.nbLots)
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.hbs', vente)
await chatMessage.update({ content: html }, { render: true })
}
}
static async displayAchatVente(vente) {
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.hbs', vente);
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.hbs', vente)
const chatMessage = await ChatMessage.create(RdDUtility.chatDataSetup(html))
await chatMessage.setFlag(SYSTEM_RDD, NB_LOTS, vente.nbLots)
await chatMessage.setFlag(SYSTEM_RDD, DETAIL_VENTE, {

View File

@@ -9,7 +9,7 @@ import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { MAINS_DIRECTRICES } from "./actor.js";
import { RdDBaseActorReveSheet } from "./actor/base-actor-reve-sheet.js";
import { ITEM_TYPES } from "./constants.js";
import { ACTOR_TYPES, ITEM_TYPES } from "./constants.js";
import { RdDItem } from "./item.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemBlessure } from "./item/blessure.js";
@@ -18,6 +18,8 @@ import { RdDBaseActorSangSheet } from "./actor/base-actor-sang-sheet.js";
import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js";
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
import { MORAL } from "./moral/apprecier.mjs";
import { RdDItemSort } from "./item-sort.js";
/* -------------------------------------------- */
/**
@@ -51,18 +53,23 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
surprise: RdDBonus.find(this.actor.getSurprise(false)).label,
resumeBlessures: this.actor.computeResumeBlessure(this.actor.system.blessures),
caracTotal: RdDCarac.computeTotal(this.actor.system.carac, this.actor.system.beaute),
caracTotalXp: RdDCarac.computeTotalXp(this.actor.system.carac, this.actor.system.beaute),
surEncombrementMessage: this.actor.isSurenc() ? "Sur-Encombrement!" : "",
malusArmure: this.actor.getMalusArmure()
})
this.timerRecherche = undefined;
if (formData.type == 'personnage') {
if (formData.type == ACTOR_TYPES.personnage) {
formData.options.mainsDirectrices = MAINS_DIRECTRICES;
formData.byCateg = Misc.classify(formData.competences, it => it.system.categorie)
formData.calc.comptageArchetype = RdDItemCompetence.computeResumeArchetype(formData.competences);
formData.calc.competenceXPTotal = RdDItemCompetence.computeTotalXP(formData.competences);
formData.calc.fatigue = RdDUtility.calculFatigueHtml(formData.system.sante.fatigue.value, formData.system.sante.endurance.max);
foundry.utils.mergeObject(formData.calc, {
comptageArchetype: RdDItemCompetence.computeResumeArchetype(formData.competences),
competenceXPTotal: RdDItemCompetence.computeTotalXP(formData.competences),
sortsXPTotal: RdDItemSort.computeTotalXP(this.actor.itemTypes[ITEM_TYPES.sort]),
fatigue: RdDUtility.calculFatigueHtml(formData.system.sante.fatigue.value, formData.system.sante.endurance.max)
})
formData.competences.forEach(item => {
item.system.isHidden = this.options.recherche
@@ -275,9 +282,9 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
this.html.find('.seuil-reve-value').change(async event => await this.actor.setPointsDeSeuil(event.currentTarget.value))
this.html.find('.stress-test').click(async event => await this.actor.transformerStress())
this.html.find('.moral-malheureux').click(async event => await this.actor.jetDeMoral('malheureuse'))
this.html.find('.moral-neutre').click(async event => await this.actor.jetDeMoral('neutre'))
this.html.find('.moral-heureux').click(async event => await this.actor.jetDeMoral('heureuse'))
this.html.find('.moral-malheureux').click(async event => await this.actor.jetDeMoral(MORAL.MALHEUREUX))
this.html.find('.moral-neutre').click(async event => await this.actor.jetDeMoral(MORAL.NEUTRE))
this.html.find('.moral-heureux').click(async event => await this.actor.jetDeMoral(MORAL.HEUREUX))
this.html.find('.button-ethylisme').click(async event => await this.actor.jetEthylisme())
this.html.find('.ptreve-actuel-plus').click(async event => await this.actor.reveActuelIncDec(1))

View File

@@ -41,17 +41,20 @@ import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemSigneDraconique } from "./item/signedraconique.js";
import { RdDRencontre } from "./item/rencontre.js";
import { DialogSelect } from "./dialog-select.js";
import { PAS_DE_DRACONIC, POSSESSION_SANS_DRACONIC } from "./item/base-items.js";
import { CATEGORIES_COMPETENCES, PAS_DE_DRACONIC, POSSESSION_SANS_DRACONIC } from "./item/base-items.js";
import { RdDRollResult } from "./rdd-roll-result.js";
import { RdDInitiative } from "./initiative.mjs";
import RollDialog from "./roll/roll-dialog.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js";
import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js";
import { ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_SORT } from "./roll/roll-constants.mjs";
import { PART_TACHE } from "./roll/roll-part-tache.mjs";
import { PART_COMP } from "./roll/roll-part-comp.mjs";
import { PART_OEUVRE } from "./roll/roll-part-oeuvre.mjs";
import { PART_CUISINE } from "./roll/roll-part-cuisine.mjs";
import { RdDPossessionV2 } from "./rdd-possession-v2.mjs";
import { Apprecier, MORAL, SITUATION_MORAL } from "./moral/apprecier.mjs";
import { Distance } from "./combat/distance.mjs";
export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre']
@@ -160,12 +163,15 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
getDemiReve() { return this.system.reve.tmrpos.coord }
getDraconics() { return this.itemTypes[ITEM_TYPES.competence].filter(it => it.system.categorie == 'draconic') }
getDraconics() {
return this.isHautRevant()
? this.itemTypes[ITEM_TYPES.competence].filter(it => it.system.categorie == CATEGORIES_COMPETENCES.draconic.key)
: []
}
getBestDraconic() { return foundry.utils.duplicate([...this.getDraconics(), PAS_DE_DRACONIC].sort(Misc.descending(it => it.system.niveau)).find(it => true)) }
getDraconicOuPossession() {
return [...this.getDraconics().filter(it => it.system.niveau >= 0), POSSESSION_SANS_DRACONIC]
.sort(Misc.descending(it => it.system.niveau))
.find(it => true)
getConjurationNaturelle() {
return new RdDItemCompetence(POSSESSION_SANS_DRACONIC)
}
isForceInsuffisante(forceRequise) {
@@ -200,7 +206,7 @@ export class RdDActor extends RdDBaseActorSang {
const niveau = comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(main) ? -8 : -6)
const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + ecaillesEfficacite
actions.push({
const attaque = {
label: arme.name + (main ? ' ' + main : ''),
action: 'attaque',
initOnly: false,
@@ -212,7 +218,9 @@ export class RdDActor extends RdDBaseActorSang {
dommages: dommages,
forceRequise: forceRequise,
initiative: RdDInitiative.getRollInitiative(caracValue, niveau, ajustement)
})
};
attaque.isDistance = Distance.typeAttaqueDistance(attaque),
actions.push(attaque)
}
addAttaque(RdDItemArme.empoignade(this), ATTAQUE_TYPE.CORPS_A_CORPS)
@@ -358,15 +366,15 @@ export class RdDActor extends RdDBaseActorSang {
content: ""
};
await this._recuperationSante(message);
await this._recupereMoralChateauDormant(message);
await this._recupereChance();
await this.transformerStress();
await this.retourSeuilDeReve(message);
await this.setBonusPotionSoin(0);
await this.retourSust(message);
await this.$perteReveEnchantementsChateauDormants();
await this.$suppressionLancementsSort();
await this._recuperationSante(message)
await this._recupereMoralChateauDormant(message)
await this._recupereChance()
await this.transformerStress()
await this.retourSeuilDeReve(message)
await this.setBonusPotionSoin(0)
await this.retourSust(message)
await this.$perteReveEnchantementsChateauDormants()
await this.$suppressionLancementsSort()
await RdDCoeur.applyCoeurChateauDormant(this, message);
if (message.content != "") {
message.content = `A la fin Chateau Dormant, ${message.content}<br>Un nouveau jour se lève`;
@@ -410,11 +418,13 @@ export class RdDActor extends RdDBaseActorSang {
}
async _recupereMoralChateauDormant(message) {
await this.update({ 'system.compteurs.bonmoments': [] }, { render: false })
if (!ReglesOptionnelles.isUsing("recuperation-moral")) { return }
const etatMoral = this.system.sommeil?.moral ?? 'neutre';
const jetMoral = await this._jetDeMoral(etatMoral);
message.content += ` -- le jet de moral est ${etatMoral}, le moral ` + this._messageAjustementMoral(jetMoral.ajustement);
const etatMoral = this.system.sommeil?.moral ?? MORAL.NEUTRE
const jetMoral = await this._jetDeMoral(etatMoral)
message.content += ` -- le jet de moral est ${etatMoral}, le moral ` + this._messageAjustementMoral(jetMoral.ajustement)
}
_messageAjustementMoral(ajustement) {
@@ -688,14 +698,14 @@ export class RdDActor extends RdDBaseActorSang {
const rencontre = await game.system.rdd.rencontresTMR.getReveDeDragon(force);
let rollData = {
actor: this,
competence: this.getDraconicOuPossession(),
competence: this.getDraconicOuPossession().find(it => true),
canClose: false,
rencontre: rencontre,
tmr: true,
use: { libre: false, conditions: false },
forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: this.getReveActuel() } }
forceCarac: this.getCaracReveActuel()
}
rollData.competence.system.defaut_carac = 'reve-actuel';
rollData.competence.system.defaut_carac = CARACS.REVE_ACTUEL
const dialog = await RdDRoll.create(this, rollData,
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-reve-de-dragon.hbs' },
@@ -1082,12 +1092,13 @@ export class RdDActor extends RdDBaseActorSang {
}
$createSortReserve(sort) {
const ptReve = Number.isInteger(sort.system.ptreve) ? Number(sort.system.ptreve) : Number(sort.system.ptreve.match(/\d+/))
this.createEmbeddedDocuments("Item",
[{
type: ITEM_TYPES.sortreserve,
name: sort.name,
img: sort.img,
system: { sortid: sort.id, draconic: sort.system.draconic, ptreve: Number(sort.system.ptreve.match(/\d+/)), coord: 'A1', heurecible: 'Vaisseau' }
system: { sortid: sort.id, draconic: sort.system.draconic, ptreve: ptReve, coord: 'A1', heurecible: 'Vaisseau' }
}],
{ renderSheet: true })
}
@@ -1191,17 +1202,21 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
async jetDeMoral(situation, messageReussi = undefined, messageManque = undefined) {
const jetMoral = await this._jetDeMoral(situation);
const finMessage = (jetMoral.succes ? messageReussi : messageManque) ?? (jetMoral.ajustement == 0 ? "Vous gardez votre moral" : jetMoral.ajustement > 0 ? "Vous gagnez du moral" : "Vous perdez du moral");
async jetDeMoral(situation, bonmoment = "") {
if (bonmoment != "" && bonmoment != undefined && this.system.compteurs.bonmoments.includes(bonmoment)) {
ui.notifications.info(`${this.name} a déjà gagné du moral après avoir passé un bon moment (${bonmoment}) pendant la journée, pas de gain de moral`)
return
}
const jetMoral = await this._jetDeMoral(situation, bonmoment)
const finMessage = (jetMoral.ajustement == 0 ? "Vous gardez votre moral" : jetMoral.ajustement > 0 ? "Vous gagnez du moral" : "Vous perdez du moral");
ChatMessage.create({
whisper: ChatUtility.getOwners(this),
content: `${finMessage} - jet ${jetMoral.succes ? "réussi" : "manqué"} en situation ${situation} (${jetMoral.jet}/${jetMoral.difficulte}).`
});
return jetMoral.ajustement;
content: `${finMessage} - jet ${jetMoral.succes ? "réussi" : "manqué"} en situation ${SITUATION_MORAL[situation] ?? situation} (${jetMoral.jet}/${jetMoral.difficulte}).`
})
return jetMoral.ajustement
}
async _jetDeMoral(situation) {
async _jetDeMoral(situation, bonmoment = "") {
const moralActuel = Misc.toInt(this.system.compteurs.moral.value);
const jet = await RdDDice.rollTotal("1d20");
const difficulte = 10 + moralActuel;
@@ -1213,14 +1228,18 @@ export class RdDActor extends RdDBaseActorSang {
difficulte: difficulte,
succes: succes,
ajustement: this._calculAjustementMoral(succes, moralActuel, situation)
};
await this.moralIncDec(jetMoral.ajustement);
}
await this.moralIncDec(jetMoral.ajustement, bonmoment);
return jetMoral;
}
/* -------------------------------------------- */
async moralIncDec(ajustementMoral) {
async moralIncDec(ajustementMoral, bonmoment = "") {
if (ajustementMoral != 0) {
if (ajustementMoral > 0 && bonmoment != "" && bonmoment != undefined) {
const bonmoments = [...this.system.compteurs.bonmoments, bonmoment]
await this.update({ 'system.compteurs.bonmoments': bonmoments }, { render: false })
}
const startMoral = parseInt(this.system.compteurs.moral.value)
const moralTheorique = startMoral + ajustementMoral
if (moralTheorique > 3) { // exaltation
@@ -1241,13 +1260,14 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
_calculAjustementMoral(succes, moral, situation) {
switch (situation) {
case 'heureux': case 'heureuse': return succes ? 1 : 0;
case 'malheureuse': case 'malheureux': return succes ? 0 : -1;
case 'neutre':
if (succes && moral < 0) return 1;
if (!succes && moral > 0) return -1;
case MORAL.TRESHEUREUX: return succes ? 2 : 1
case MORAL.HEUREUX: case 'heureuse': return succes ? 1 : 0
case MORAL.MALHEUREUX: case 'malheureuse': return succes ? 0 : -1
case MORAL.NEUTRE:
if (succes && moral < 0) return 1
if (!succes && moral > 0) return -1
}
return 0;
return 0
}
/* -------------------------------------------- */
@@ -1296,6 +1316,15 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async consommerNourritureboisson(itemId, choix = { doses: 1, seForcer: false, supprimerSiZero: false }) {
const item = this.getItem(itemId)
if (!item.getUtilisationCuisine()) {
return
}
if (choix.doses > item.system.quantite) {
ui.notifications.warn(`Il n'y a pas assez de ${item.name} pour manger ${choix.doses}`)
return
}
if (!this.isOwner) {
RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
@@ -1304,35 +1333,26 @@ export class RdDActor extends RdDBaseActorSang {
})
return
}
const item = this.getItem(itemId)
if (!item.getUtilisationCuisine()) {
return;
}
if (choix.doses > item.system.quantite) {
ui.notifications.warn(`Il n'y a pas assez de ${item.name} pour manger ${choix.doses}`)
return;
}
if (!this._apprecierCuisine(item, choix.seForcer)) {
ui.notifications.info(`${this.name} ne n'arrive pas à manger de ${item.name}`)
return;
}
await this.manger(item, choix.doses, { diminuerQuantite: false });
await this.boire(item, choix.doses, { diminuerQuantite: false });
await item.diminuerQuantite(choix.doses, choix);
}
async _apprecierCuisine(item, seForcer) {
const surmonteExotisme = await this._surmonterExotisme(item, seForcer);
if (surmonteExotisme) {
await this.apprecier(CARACS.ODORATGOUT, 'cuisine', item.system.qualite, item.system.boisson ? "apprécie la boisson" : "apprécie le plat");
if (await this._surmonterExotisme(item)) {
if (item.system.qualite > 0) {
new Apprecier(this, item.system.appreciation, item.system.qualite).apprecier()
}
await this.onConsommerNourritureboisson(item, choix)
}
else if (seForcer) {
await this.jetDeMoral('malheureux');
else if (choix.seForcer) {
await this.jetDeMoral(MORAL.MALHEUREUX)
await this.onConsommerNourritureboisson(item, choix)
}
else {
return false;
ui.notifications.info(`${this.name} ne n'arrive pas à manger de ${item.name}`)
}
return true;
}
async onConsommerNourritureboisson(item, choix) {
await this.manger(item, choix.doses, { diminuerQuantite: false })
await this.boire(item, choix.doses, { diminuerQuantite: false })
await item.diminuerQuantite(choix.doses, choix)
}
/* -------------------------------------------- */
@@ -1345,7 +1365,7 @@ export class RdDActor extends RdDBaseActorSang {
const rolled = await this.doRollCaracCompetence(CARACS.VOLONTE, competence, difficulte, { title: `tente de surmonter l'exotisme de ${item.name}` })
return rolled.isSuccess
}
return true;
return true
}
/* -------------------------------------------- */
@@ -1358,7 +1378,7 @@ export class RdDActor extends RdDBaseActorSang {
}
const rolled = await this.doRollCaracCompetence(carac, undefined, 0, { title });
if (rolled?.isSuccess) {
await this.jetDeMoral('heureux');
await this.jetDeMoral(MORAL.HEUREUX);
}
}
@@ -1425,7 +1445,7 @@ export class RdDActor extends RdDBaseActorSang {
ethylismeData.perteEndurance = await this.santeIncDec("endurance", -perte);
if (!ethylisme.jet_moral) {
ethylismeData.jetMoral = await this._jetDeMoral('heureuse');
ethylismeData.jetMoral = await this._jetDeMoral(MORAL.HEUREUX, "Ethylisme");
if (ethylismeData.jetMoral.ajustement == 1) {
ethylismeData.moralAlcool = 'heureux';
ethylisme.jet_moral = true;
@@ -1433,7 +1453,7 @@ export class RdDActor extends RdDBaseActorSang {
ethylismeData.jetMoral.ajustement = -1;
ethylismeData.moralAlcool = 'triste';
ethylisme.jet_moral = true;
await this.moralIncDec(-1);
await this.moralIncDec(-1, "Ethylisme");
}
}
if (ethylisme.value < 0) {
@@ -1916,7 +1936,7 @@ export class RdDActor extends RdDBaseActorSang {
async getTacheBlessure(blesse, blessure) {
const gravite = blessure?.system.gravite ?? 0;
if (gravite > 0) {
const tache = this.itemTypes['tache'].find(it => it.system.itemId == blessure.id)
const tache = this.itemTypes[ITEM_TYPES.tache].find(it => it.system.itemId == blessure.id)
?? await RdDItemBlessure.createTacheSoinBlessure(this, gravite);
await blessure?.updateTacheSoinBlessure(tache);
return tache
@@ -1936,7 +1956,7 @@ export class RdDActor extends RdDBaseActorSang {
diff: { value: diff ?? 0 }
}
}
return await RollDialog.create(rollData)
return await RollDialog.create(rollData, options)
}
RdDEmpoignade.checkEmpoignadeEnCours(this)
@@ -1970,7 +1990,7 @@ export class RdDActor extends RdDBaseActorSang {
selected: { tache: { key: tache.id, forced: options.forced } },
type: { allowed: [PART_TACHE], current: PART_TACHE }
}
return await RollDialog.create(rollData)
return await RollDialog.create(rollData, options)
}
const compData = this.getCompetence(tache.system.competence)
@@ -2014,8 +2034,8 @@ export class RdDActor extends RdDBaseActorSang {
await this.santeIncDec("fatigue", rollData.tache.system.fatigue);
await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-tache.hbs');
if (options?.onRollAutomate) {
options.onRollAutomate(rollData);
if (options?.callbacks) {
await Promise.all(callbacks.map(callback => callback(rollData)))
}
}
@@ -2484,79 +2504,18 @@ export class RdDActor extends RdDBaseActorSang {
const blessure = blesse.blessuresASoigner().find(it => it.id == blessureId);
if (blessure) {
if (!blessure.system.premierssoins.done) {
const tache = await this.getTacheBlessure(blesse, blessure);
return await this.rollTache(tache.id, {
onRollAutomate: async r => blesse.onRollTachePremiersSoins(blessureId, r),
title: 'Premiers soins',
forced: true
const tacheId = (await this.getTacheBlessure(blesse, blessure))?.id
return await this.rollTache(tacheId, {
callbacks: [async r => await blesse.callbackPremiersSoins(blessureId, r, this.id)],
title: 'Premiers soins', forced: true
});
}
else if (!blessure.system.soinscomplets.done) {
const diff = blessure.system.difficulte + (blessure.system.premierssoins.bonus ?? 0);
return await this.rollCaracCompetence(CARACS.DEXTERITE, "Chirurgie", diff, {
title: "Soins complets",
onRollAutomate: r => blesse.onRollSoinsComplets(blessureId, r),
forced: true
})
}
}
}
async onRollTachePremiersSoins(blessureId, rollData) {
if (!this.isOwner) {
return RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
method: 'onRollTachePremiersSoins', args: [blessureId, rollData]
})
}
const blessure = this.getItem(blessureId, 'blessure')
if (blessure && !blessure.system.premierssoins.done) {
const tache = rollData.tache;
if (rollData.rolled.isETotal) {
await blessure.update({
'system.difficulte': blessure.system.difficulte - 1,
'system.premierssoins.tache': Math.max(0, tache.system.points_de_tache_courant)
})
}
else {
const bonus = tache.system.points_de_tache_courant - tache.system.points_de_tache
await blessure.update({
'system.premierssoins': {
done: (bonus >= 0),
bonus: Math.max(0, bonus),
tache: Math.max(0, tache.system.points_de_tache_courant)
}
})
if (bonus >= 0) {
await this.deleteEmbeddedDocuments('Item', [tache.id])
}
}
}
}
async onRollSoinsComplets(blessureId, rollData) {
if (!this.isOwner) {
return RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
method: 'onRollSoinsComplets', args: [blessureId, rollData]
})
}
const blessure = this.getItem(blessureId, 'blessure')
if (blessure && blessure.system.premierssoins.done && !blessure.system.soinscomplets.done) {
// TODO: update de la blessure: passer par le MJ!
if (rollData.rolled.isETotal) {
await blessure.setSoinsBlessure({
difficulte: blessure.system.difficulte - 1,
premierssoins: { done: false, bonus: 0 }, soinscomplets: { done: false, bonus: 0 },
})
}
else {
// soins complets finis
await blessure.setSoinsBlessure({
soinscomplets: { done: true, bonus: Math.max(0, rollData.rolled.ptTache) },
callbacks: [async r => await blesse.onRollSoinsComplets(blessureId, r, this.id)],
onRollDone: RollDialog.onRollDoneClose,
title: "Soins complets", forced: true
})
}
}
@@ -2564,7 +2523,12 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
conjurerPossession(possession) {
RdDPossession.onConjurerPossession(this, possession)
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
RdDPossessionV2.rollConjurerPossession(this, possession)
}
else {
RdDPossession.onConjurerPossession(this, possession)
}
}
/* -------------------------------------------- */
@@ -2967,15 +2931,6 @@ export class RdDActor extends RdDBaseActorSang {
await this.diminuerQuantiteObjet(potion.id, 1, { supprimerSiZero: potion.supprimer });
}
/* -------------------------------------------- */
async onUpdateActor(update, options, actorId) {
const updatedEndurance = update?.system?.sante?.endurance
if (updatedEndurance && options.diff) {
await this.setEffect(STATUSES.StatusUnconscious, updatedEndurance.value == 0)
}
await super.onUpdateActor(update, options, actorId)
}
/* -------------------------------------------- */
async onPreUpdateItem(item, change, options, id) {
if (item.isCompetencePersonnage() && item.system.defaut_carac && item.system.xp) {

View File

@@ -1,4 +1,4 @@
import { renderTemplate, SHOW_DICE, SYSTEM_RDD } from "../constants.js";
import { RDD_CONFIG, renderTemplate, SHOW_DICE, SYSTEM_RDD } from "../constants.js";
import { Grammar } from "../grammar.js";
import { Misc } from "../misc.js";
import { RdDResolutionTable } from "../rdd-resolution-table.js";
@@ -22,13 +22,16 @@ import { DialogValidationEncaissement } from "../dialog-validation-encaissement.
import { RdDCombat } from "../rdd-combat.js";
import { RdDEmpoignade } from "../rdd-empoignade.js";
import { RdDPossession } from "../rdd-possession.js";
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, POSSESSION_SANS_DRACONIC } from "../item/base-items.js";
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, CATEGORIES_COMPETENCES_CREATURES } from "../item/base-items.js";
import { RollDataAjustements } from "../rolldata-ajustements-v1.js";
import { MappingCreatureArme } from "../item/mapping-creature-arme.mjs";
import RollDialog from "../roll/roll-dialog.mjs";
import { ATTAQUE_ROLL_TYPES, DEFAULT_ROLL_TYPES, DIFF, DIFFS, ROLL_TYPE_ATTAQUE, ROLL_TYPE_COMP, ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_OEUVRE, ROLL_TYPE_TACHE } from "../roll/roll-constants.mjs";
import { ATTAQUE_ROLL_TYPES, DEFAULT_ROLL_TYPES, DIFF, ROLL_TYPE_ATTAQUE } from "../roll/roll-constants.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2 } from "../settings/options-avancees.js";
import { PART_COMP } from "../roll/roll-part-comp.mjs";
import { RdDInitiative } from "../initiative.mjs";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
import { RdDPossessionV2 } from "../rdd-possession-v2.mjs";
/**
* Classe de base pour les acteurs disposant de rêve (donc, pas des objets)
@@ -45,39 +48,24 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
getCarac() {
return foundry.utils.mergeObject(this.system.carac,
{
'reve-actuel': this.getCaracReveActuel(),
'chance-actuelle': this.getCaracChanceActuelle()
},
{ inplace: false })
}
getCaracChanceActuelle() {
return {
label: 'Chance actuelle',
value: this.getChanceActuel(),
type: "number"
};
}
getCaracReveActuel() {
return {
label: 'Rêve actuel',
value: this.getReveActuel(),
type: "number"
};
const carac = super.getCarac()
foundry.utils.mergeObject(carac, this.getCaracReveActuel())
foundry.utils.mergeObject(carac, this.getCaracCompetenceCreature(), { overwrite: false })
return carac
}
getTaille() { return Misc.toInt(this.system.carac.taille?.value) }
getConstitution() { return this.getReve() }
getForce() { return this.getReve() }
getAgilite() { return this.getForce() }
getReve() { return Misc.toInt(this.system.carac.reve?.value) }
getChance() { return this.getReve() }
getChanceActuel() { return this.getChance() }
getCaracChanceActuelle() { return { [CARACS.CHANCE_ACTUELLE]: { label: 'Chance actuelle', value: this.getChanceActuel(), type: "number" } } }
getReveActuel() { return this.getReve() }
getChanceActuel() { return this.getChance() }
getCaracReveActuel() { return { [CARACS.REVE_ACTUEL]: { label: "Rêve Actuel", value: this.getReveActuel(), type: "number" } } }
getEnduranceMax() { return Math.max(1, this.getTaille() + this.getConstitution()) }
getEncombrementMax() { return (this.getForce() + this.getTaille()) / 2 }
@@ -114,11 +102,54 @@ export class RdDBaseActorReve extends RdDBaseActor {
return this.system.carac[competence.system.defaut_carac].value;
}
getDraconics() { return [] }
getDraconicOuPossession() {
return [
...this.getDraconics(),
...this.itemTypes[ITEM_TYPES.competencecreature].filter(it => it.isCompetencePossession()),
this.getConjurationNaturelle()
].sort(Misc.descending(it => it.system.niveau));
}
getConjurations() {
return this.getDraconicOuPossession()
.map(it => this.toActionConjuration(it))
}
getConjurationNaturelle() {
return new RdDItemCompetenceCreature({
name: 'Sans compétence',
type: ITEM_TYPES.competencecreature,
img: RDD_CONFIG.icons.possession,
system: {
carac_value: this.getReveActuel(),
niveau: 0,
default_diffLibre: 0,
categorie: CATEGORIES_COMPETENCES_CREATURES.possession.key,
ispossession: true,
}
})
}
toActionConjuration(comp) {
const caracCode = this.isPersonnage() ? CARACS.REVE_ACTUEL : CARACS.REVE
const caracValue = this.getReveActuel()
const ajustement = this.getEtatGeneral()
return {
label: `Conjuration (${comp.name})`,
action: 'possession',
initOnly: false,
comp: comp,
carac: { key: caracCode, value: caracValue },
initiative: RdDInitiative.getRollInitiative(caracValue, comp.system.niveau, ajustement)
}
}
listActions({ isAttaque = false, isEquipe = false }) {
return this.itemTypes[ITEM_TYPES.competencecreature]
.filter(it => it.isAttaque())
.map(it => it.attaqueCreature())
.filter(it => it != undefined);
.filter(it => it != undefined)
}
async computeArmure(dmg) { return this.getProtectionNaturelle() }
@@ -130,13 +161,14 @@ export class RdDBaseActorReve extends RdDBaseActor {
async santeIncDec(name, inc, isCritique = false) { }
async finDeRound(options = { terminer: false }) {
await this.$finDeRoundSuppressionEffetsTermines(options);
await this.finDeRoundBlessures();
await this.$finDeRoundSupprimerObsoletes();
await this.$finDeRoundEmpoignade();
await this.finDeRoundSuppressionEffetsTermines(options)
await this.finDeRoundBlessures()
await this.finDeRoundSupprimerObsoletes()
await this.finDeRoundEmpoignade()
await this.finDeRoundPossession()
}
async $finDeRoundSuppressionEffetsTermines(options) {
async finDeRoundSuppressionEffetsTermines(options) {
for (let effect of this.getEffects()) {
if (effect.duration.type !== 'none' && (effect.duration.remaining <= 0 || options.terminer)) {
await effect.delete();
@@ -148,20 +180,24 @@ export class RdDBaseActorReve extends RdDBaseActor {
async finDeRoundBlessures() {
}
async $finDeRoundSupprimerObsoletes() {
async finDeRoundSupprimerObsoletes() {
const obsoletes = []
.concat(this.itemTypes[ITEM_TYPES.empoignade].filter(it => it.system.pointsemp <= 0))
.concat(this.itemTypes[ITEM_TYPES.possession].filter(it => it.system.compteur < -2 || it.system.compteur > 2))
.map(it => it.id);
.map(it => it.id)
await this.deleteEmbeddedDocuments('Item', obsoletes);
}
async $finDeRoundEmpoignade() {
async finDeRoundEmpoignade() {
await Promise.all(this.itemTypes[ITEM_TYPES.empoignade]
.filter(it => it.system.pointsemp >= 2 && it.system.empoigneurid == this.id)
.map(async it => await RdDEmpoignade.onImmobilisation(this, it)))
}
async finDeRoundPossession() {
await Promise.all(this.itemTypes[ITEM_TYPES.possession]
.map(async it => await RdDPossessionV2.onPossession(this, it)))
}
async setSonne(sonne = true) { }
/* -------------------------------------------- */
@@ -198,8 +234,6 @@ export class RdDBaseActorReve extends RdDBaseActor {
return false
}
getDraconicOuPossession() { return POSSESSION_SANS_DRACONIC }
getPossession(possessionId) {
return this.itemTypes[ITEM_TYPES.possession].find(it => it.system.possessionid == possessionId);
}
@@ -208,6 +242,13 @@ export class RdDBaseActorReve extends RdDBaseActor {
return this.itemTypes[ITEM_TYPES.empoignade];
}
async updateCarac(caracName, to) {
const path = `system.carac.${caracName}.value`;
let updates = {};
updates[path] = Number.parseInt(to)
await this.update(updates, { noHook: true });
}
/* -------------------------------------------- */
async updateCreatureCompetence(idOrName, fieldName, value) {
let competence = this.getCompetence(idOrName);
@@ -299,7 +340,10 @@ export class RdDBaseActorReve extends RdDBaseActor {
competence: competence,
show: { title: options?.title ?? '' }
},
callbacks: [async r => this.$onRollCompetence(r, options)]
callbacks: [
async r => this.$onRollCompetence(r, options),
...(options?.callbacks ?? [])
]
});
}
/**
@@ -336,6 +380,19 @@ export class RdDBaseActorReve extends RdDBaseActor {
/* -------------------------------------------- */
async roll() {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: {
allowed: DEFAULT_ROLL_TYPES,
current: PART_COMP,
},
selected: {
diff: { type: DIFF.DEFAUT }
}
}
return await RollDialog.create(rollData)
}
RdDEmpoignade.checkEmpoignadeEnCours(this)
const carac = this.getCarac()
@@ -425,17 +482,15 @@ export class RdDBaseActorReve extends RdDBaseActor {
async rollCompetence(idOrName, options = { tryTarget: true, arme: undefined }) {
RdDEmpoignade.checkEmpoignadeEnCours(this)
const competence = this.getCompetence(idOrName);
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: { allowed: options.arme ? ATTAQUE_ROLL_TYPES : DEFAULT_ROLL_TYPES },
type: { allowed: DEFAULT_ROLL_TYPES },
selected: {
carac: competence.type == ITEM_TYPES.competencecreature ? { key: competence.name } : undefined,
comp: { key: competence.name },
diff: { type: options.arme ? DIFF.ATTAQUE : DIFF.LIBRE, value: competence.system.default_diffLibre ?? 0 },
attaque: options.arme ? { arme: { key: options.arme.id } } : undefined
diff: { type: DIFF.LIBRE, value: competence.system.default_diffLibre ?? 0 },
}
}
return await RollDialog.create(rollData)
@@ -507,7 +562,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
type: {
allowed: [ROLL_TYPE_ATTAQUE], current: ROLL_TYPE_ATTAQUE
}
};
}
return await RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose })
}
})
@@ -516,16 +571,18 @@ export class RdDBaseActorReve extends RdDBaseActor {
/** --------------------------------------------
* @param {*} arme item d'arme/compétence de créature
* @param {*} categorieArme catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession
* @param {*} maniement catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession
* @returns
*/
rollArme(arme, categorieArme = 'competence', token = undefined) {
async rollArme(arme, maniement = 'competence', token = undefined) {
token = token ?? RdDUtility.getSelectedToken(this)
const compToUse = RdDItemArme.getCompetenceArme(arme, categorieArme)
const compToUse = RdDItemArme.getCompetenceArme(arme, maniement)
if (!RdDItemArme.isUtilisable(arme)) {
ui.notifications.warn(`Arme inutilisable: ${arme.name} non équipée ou avec une résistance de 0 ou moins`)
return
}
if (!Targets.hasTargets()) {
RdDConfirm.confirmer({
settingConfirmer: "confirmer-combat-sans-cible",
@@ -537,7 +594,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
onAction: async () => {
this.rollCompetence(compToUse, { tryTarget: false, arme: arme })
}
});
})
return
}
@@ -547,14 +604,19 @@ export class RdDBaseActorReve extends RdDBaseActor {
return
}
const competence = this.getCompetence(compToUse)
if (competence.isCompetencePossession()) {
return RdDPossession.onAttaquePossession(target, this, competence);
const comp = this.getCompetence(compToUse)
if (comp.isCompetencePossession()) {
// TODO: vérifier si c'est possible, sinon simplifier
return RdDPossession.onAttaquePossession(target, this, comp);
}
RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme);
RdDCombat.rddCombatTarget(target, this, token).attaque(comp, arme, maniement)
})
}
rollPossession() {
RdDPossessionV2.rollAttaquePossession(this)
}
verifierForceMin(item) { }
/* -------------------------------------------- */

View File

@@ -7,6 +7,8 @@ import { RdDDice } from "../rdd-dice.js";
import { RdDItemBlessure } from "../item/blessure.js";
import { ChatUtility } from "../chat-utility.js";
import { Misc } from "../misc.js";
import { RdDBaseActor } from "./base-actor.js";
import { CARACS } from "../rdd-carac.js";
/**
* Classe de base pour les acteurs qui peuvent subir des blessures
@@ -22,10 +24,18 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
this.system.attributs.encombrement.value = this.getEncombrementMax()
}
getCarac() {
const carac = super.getCarac()
foundry.utils.mergeObject(carac, this.getCaracChanceActuelle())
foundry.utils.mergeObject(carac, this.getCaracVie())
return carac
}
getForce() { return Misc.toInt(this.system.carac.force?.value) }
getConstitution() { return Misc.toInt(this.system.carac.constitution?.value) }
getVolonte() { return Misc.toInt(this.system.carac.volonte?.value) }
getCaracVie() { return { [CARACS.VIE]: { label: "Vie", value: this.getVieMax(), type: "number" } } }
getVieMax() { return Misc.toInt(this.system.sante.vie?.max) }
getEnduranceMax() { return Math.max(1, this.getTaille() + this.getConstitution()) }
getFatigueMax() { return this.getEnduranceMax() * 2 }
@@ -120,16 +130,14 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
/* -------------------------------------------- */
async santeIncDec(name, inc, isCritique = false) {
if (name == 'fatigue' && !ReglesOptionnelles.isUsing("appliquer-fatigue")) {
return;
return
}
if (!this.system.sante[name]) {
return
}
const sante = foundry.utils.duplicate(this.system.sante)
let compteur = sante[name];
if (!compteur) {
return;
}
let result = {
sonne: false,
};
const compteur = sante[name]
const result = { sonne: false }
let perteEndurance = 0
let minValue = name == "vie" ? -this.getSConst() - 1 : 0;
@@ -171,6 +179,72 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
return result
}
async callbackPremiersSoins(blessureId, rollData, soigneurId) {
await this.onRollTachePremiersSoins(blessureId,
rollData.v2 ? rollData.current.tache.tache : rollData.tache,
rollData.rolled.isETotal,
soigneurId)
}
async onRollTachePremiersSoins(blessureId, tache, isETotal, soigneurId) {
if (!this.isOwner) {
return RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
method: 'onRollTachePremiersSoins', args: [blessureId, tache, isETotal, soigneurId]
})
}
const blessure = this.getItem(blessureId, 'blessure')
if (blessure && !blessure.system.premierssoins.done) {
if (isETotal) {
await blessure.update({
'system.difficulte': blessure.system.difficulte - 1,
'system.premierssoins.tache': Math.max(0, tache.system.points_de_tache_courant)
})
}
else {
const bonus = tache.system.points_de_tache_courant - tache.system.points_de_tache
await blessure.update({
'system.premierssoins': {
done: (bonus >= 0),
bonus: Math.max(0, bonus),
tache: Math.max(0, tache.system.points_de_tache_courant)
}
})
if (bonus >= 0 && soigneurId) {
const soigneur = game.actors.get(soigneurId)
await soigneur.deleteEmbeddedDocuments('Item', [tache.id], { render: true })
}
}
}
}
async onRollSoinsComplets(blessureId, rollData) {
if (!this.isOwner) {
return RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
method: 'onRollSoinsComplets', args: [blessureId, rollData]
})
}
const blessure = this.getItem(blessureId, 'blessure')
if (blessure && blessure.system.premierssoins.done && !blessure.system.soinscomplets.done) {
// TODO: update de la blessure: passer par le MJ!
if (rollData.rolled.isETotal) {
await blessure.setSoinsBlessure({
difficulte: blessure.system.difficulte - 1,
premierssoins: { done: false, bonus: 0 }, soinscomplets: { done: false, bonus: 0 },
})
}
else {
// soins complets finis
await blessure.setSoinsBlessure({
soinscomplets: { done: true, bonus: Math.max(0, rollData.rolled.ptTache) },
})
}
}
}
/* -------------------------------------------- */
_computeEnduranceMax() {
const diffVie = this.system.sante.vie.max - this.system.sante.vie.value;
@@ -182,14 +256,22 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
return Math.max(0, Math.min(maxEndVie, maxEndGraves, maxEndCritiques));
}
async onUpdateActor(update, options, actorId) {
const updatedEndurance = update?.system?.sante?.endurance
if (updatedEndurance && options.diff) {
await this.setEffect(STATUSES.StatusUnconscious, updatedEndurance.value == 0)
}
await super.onUpdateActor(update, options, actorId)
}
async onCreateItem(item, options, id) {
await this.changeItemEffects(item)
await super.onCreateItem(item, options, id)
}
async onUpdateItem(item, options, id) {
async onUpdateItem(item, updates, options, id) {
await this.changeItemEffects(item);
await super.onUpdateItem(item, options, id)
await super.onUpdateItem(item, updates, options, id)
}
async onDeleteItem(item, options, id) {

View File

@@ -11,6 +11,8 @@ import { RdDUtility } from "../rdd-utility.js";
import { SystemCompendiums } from "../settings/system-compendiums.js";
import { RdDItem } from "../item.js";
import { StatusEffects, STATUSES } from "../settings/status-effects.js";
import { Apprecier } from "../moral/apprecier.mjs";
import { CARACS } from "../rdd-carac.js";
export class RdDBaseActor extends Actor {
@@ -22,7 +24,7 @@ export class RdDBaseActor extends Actor {
}
static $findCaracByName(carac, name) {
const caracList = Object.entries(carac);
const caracList = Object.entries(carac)
let entry = Misc.findFirstLike(name, caracList, { mapper: it => it[0], description: 'caractéristique', onMessage: m => { } });
if (!entry || entry.length == 0) {
entry = Misc.findFirstLike(name, caracList, { mapper: it => it[1].label, description: 'caractéristique' });
@@ -49,7 +51,7 @@ export class RdDBaseActor extends Actor {
Handlebars.registerHelper('actor-isFeminin', actor => actor.isFeminin())
Hooks.on("preUpdateItem", (item, change, options, id) => Misc.documentIfResponsible(item.parent)?.onPreUpdateItem(item, change, options, id))
Hooks.on("createItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onCreateItem(item, options, id))
Hooks.on("updateItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onUpdateItem(item, options, id))
Hooks.on("updateItem", (item, updates, options, id) => Misc.documentIfResponsible(item.parent)?.onUpdateItem(item, updates, options, id))
Hooks.on("deleteItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onDeleteItem(item, options, id))
Hooks.on("updateActor", (actor, change, options, actorId) => Misc.documentIfResponsible(actor)?.onUpdateActor(change, options, actorId))
}
@@ -61,25 +63,29 @@ export class RdDBaseActor extends Actor {
}
}
static remoteActorCall(callData) {
static remoteActorCall(callData, userId = undefined) {
if (game.user.isGM) {
RdDBaseActor.onRemoteActorCall(callData, game.user.id)
return false
}
else {
game.socket.emit(SYSTEM_SOCKET_ID, {
msg: "msg_remote_actor_call",
data: callData,
userId: Misc.firstConnectedGMId()
})
return true
const gmUserId = Misc.firstConnectedGMId()
if (gmUserId) {
game.socket.emit(SYSTEM_SOCKET_ID, {
msg: "msg_remote_actor_call",
data: callData,
userId: gmUserId
})
return true
}
return false
}
}
static onRemoteActorCall(callData, userId) {
const actor = RdDBaseActor.getRealActor(callData?.actorId, callData?.tokenId);
if (userId == game.user.id) {
// Seul le joueur choisi effectue l'appel: le joueur courant si propriétaire de l'actor, ou le MJ sinon
const actor = RdDBaseActor.getRealActor(callData?.actorId, callData?.tokenId);
const args = callData.args;
console.info(`RdDBaseActor.onRemoteActorCall: pour l'Actor ${callData.actorId}, appel de RdDBaseActor.${callData.method}(`, ...args, ')');
actor[callData.method](...args);
@@ -150,30 +156,47 @@ export class RdDBaseActor extends Actor {
super(docData, context);
}
getCarac() {
return foundry.utils.duplicate(this.system.carac)
}
findCaracByName(name) {
name = Grammar.toLowerCaseNoAccent(name)
switch (name) {
case 'reve-actuel': case 'reve actuel':
return this.system.carac.reve
case 'chance-actuelle': case 'chance actuelle':
return this.system.carac.chance
case 'vie':
return this.system.sante.vie
case 'reve actuel':
name = CARACS.REVE_ACTUEL
break
case 'chance actuelle':
name = CARACS.CHANCE_ACTUELLE
break
}
const carac = this.system.carac;
const carac = this.getCarac()
return RdDBaseActor.$findCaracByName(carac, name);
}
getCaracCompetenceCreature() {
return this.isCreatureOuEntite()
? Object.fromEntries(this.itemTypes[ITEM_TYPES.competencecreature].map(it => [Grammar.toLowerCaseNoAccent(it.name), { label: it.name, value: it.system.carac_value }]))
: {}
}
mapCarac(caracCode) { return caracCode }
getCaracByName(name) {
name = this.mapCarac(Grammar.toLowerCaseNoAccent(name))
name = this.mapCarac(Grammar.toLowerCaseNoAccent(name)) ?? name
switch (name) {
case 'reve-actuel': case 'reve actuel':
return this.getCaracReveActuel();
case 'chance-actuelle': case 'chance-actuelle':
return this.getCaracChanceActuelle();
case 'reve actuel':
name = CARACS.REVE_ACTUEL
break
case 'chanceactuelle':
name = CARACS.CHANCE_ACTUELLE
break
}
switch (name) {
case CARACS.REVE_ACTUEL:
return this.getCaracReveActuel()[CARACS.REVE_ACTUEL]
case CARACS.CHANCE_ACTUELLE:
return this.getCaracChanceActuelle()[CARACS.CHANCE_ACTUELLE]
}
return this.findCaracByName(name);
}
@@ -220,6 +243,7 @@ export class RdDBaseActor extends Actor {
isEntite() { return false }
isEntiteIncarnee() { return false }
isEntiteNonIncarnee() { return false }
isEntiteBlurette() { return false }
isHautRevant() { return false }
isVehicule() { return false }
isPersonnage() { return false }
@@ -316,7 +340,9 @@ export class RdDBaseActor extends Actor {
async onCreateItem(item, options, id) {
}
async onUpdateItem(item, options, id) {
async onUpdateItem(item, updates, options, id) {
const conteneur = item.findConteneur()
conteneur?.render(options.render)
}
async onDeleteItem(item, options, id) {
@@ -325,9 +351,8 @@ export class RdDBaseActor extends Actor {
}
}
async _removeItemFromConteneur(item) {
const updates = this.items.filter(it => it.isConteneur() && it.system.contenu.includes(item.id))
const updates = this.findConteneur(item)
.map(conteneur => {
const nouveauContenu = conteneur.system.contenu.filter(id => id != item.id)
return { _id: conteneur.id, 'system.contenu': nouveauContenu }
@@ -357,7 +382,7 @@ export class RdDBaseActor extends Actor {
/* -------------------------------------------- */
async cleanupConteneurs() {
if (Misc.isOwnerPlayer(this)) {
let updates = this.itemTypes['conteneur']
let updates = this.itemTypes[ITEM_TYPES.conteneur]
.filter(c => c.system.contenu.filter(id => this.getItem(id) == undefined).length > 0)
.map(c => { return { _id: c._id, 'system.contenu': c.system.contenu.filter(id => this.getItem(id) != undefined) } });
if (updates.length > 0) {
@@ -368,7 +393,7 @@ export class RdDBaseActor extends Actor {
/* -------------------------------------------- */
getFortune() {
return Monnaie.getFortune(this.itemTypes['monnaie']);
return Monnaie.getFortune(this.itemTypes[ITEM_TYPES.monnaie]);
}
/* -------------------------------------------- */
@@ -411,6 +436,14 @@ export class RdDBaseActor extends Actor {
}
async depenserSols(sols) {
if (!this.isOwner) {
return RdDBaseActor.remoteActorCall({
userId: Misc.connectedGMOrUser(),
tokenId: this.token?.id,
actorId: this.id,
method: 'depenserSols', args: [sols]
})
}
let reste = this.getFortune() - Number(sols);
if (reste >= 0) {
await Monnaie.optimiserFortune(this, reste);
@@ -419,32 +452,31 @@ export class RdDBaseActor extends Actor {
}
async ajouterSols(sols, fromActorId = undefined) {
sols = Number(sols);
sols = Number(sols)
if (sols == 0) {
return;
return
}
if (sols < 0) {
ui.notifications.error(`Impossible d'ajouter un gain de ${sols} <0`);
return;
ui.notifications.error(`Impossible d'ajouter un gain de ${sols} <0`)
return
}
if (fromActorId && !this.isOwner) {
RdDBaseActor.remoteActorCall({
return RdDBaseActor.remoteActorCall({
userId: Misc.connectedGMOrUser(),
tokenId: this.token?.id,
actorId: this.id,
method: 'ajouterSols', args: [sols, fromActorId]
});
})
}
else {
const fromActor = game.actors.get(fromActorId)
await Monnaie.optimiserFortune(this, sols + this.getFortune());
RdDAudio.PlayContextAudio("argent"); // Petit son
ChatMessage.create({
whisper: ChatUtility.getOwners(this),
content: `Vous avez reçu <strong>${sols} Sols</strong> ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.`
});
}
const fromActor = game.actors.get(fromActorId)
await Monnaie.optimiserFortune(this, sols + this.getFortune());
RdDAudio.PlayContextAudio("argent"); // Petit son
ChatMessage.create({
whisper: ChatUtility.getOwners(this),
content: `Vous avez reçu <strong>${sols} Sols</strong> ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.`
})
}
/* -------------------------------------------- */
@@ -456,24 +488,28 @@ export class RdDBaseActor extends Actor {
/* -------------------------------------------- */
async achatVente(achat) {
if (achat.vendeurId == achat.acheteurId) {
ui.notifications.info("Inutile de se vendre à soi-même");
return;
ui.notifications.info("Inutile de se vendre à soi-même")
return
}
if (!Misc.isFirstConnectedGM()) {
const cout = Number(achat.prixTotal ?? 0)
const acheteur = achat.acheteurId ? game.actors.get(achat.acheteurId) : undefined
if (acheteur && !acheteur.isOwner) {
ui.notifications.warn(`${game.user.id} n'est pas propriétaire de ${this.name} et effectue un achat pour lui!`)
RdDBaseActor.remoteActorCall({
actorId: achat.vendeurId ?? achat.acheteurId,
actorId: achat.acheteurId,
method: 'achatVente', args: [achat]
});
return
}
const cout = Number(achat.prixTotal ?? 0);
const vendeur = achat.vendeurId ? game.actors.get(achat.vendeurId) : undefined;
const acheteur = achat.acheteurId ? game.actors.get(achat.acheteurId) : undefined;
const vendeur = achat.vendeurId ? game.actors.get(achat.vendeurId) : undefined
const quantite = (achat.choix.nombreLots ?? 1) * (achat.vente.tailleLot);
const itemVendu = vendeur?.getItem(achat.vente.item._id) ?? game.items.get(achat.vente.item._id);
if (!itemVendu) {
ChatUtility.notifyUser(achat.userId, 'warn', vendeur ? `Le vendeur n'a pas plus de ${achat.vente.item.name} !` : `Impossible de retrouver: ${achat.vente.item.name} !`);
return;
return
}
if (vendeur && !vendeur.verifierQuantite(itemVendu, quantite)) {
ChatUtility.notifyUser(achat.userId, 'warn', `Le vendeur n'a pas assez de ${itemVendu.name} !`);
@@ -481,10 +517,10 @@ export class RdDBaseActor extends Actor {
}
if (acheteur && !acheteur.verifierFortune(cout)) {
ChatUtility.notifyUser(achat.userId, 'warn', `Vous n'avez pas assez d'argent pour payer ${Math.ceil(cout / 100)} sols !`);
return;
return
}
await vendeur?.vendre(itemVendu, quantite, cout);
await acheteur?.acheter(itemVendu, quantite, cout, achat)
await vendeur?.vendre(itemVendu, quantite, cout, acheteur);
await acheteur?.acheter(itemVendu, quantite, cout, achat, vendeur)
if (cout > 0) {
RdDAudio.PlayContextAudio("argent");
@@ -499,27 +535,40 @@ export class RdDBaseActor extends Actor {
});
if (!achat.vente.quantiteIllimite) {
if (achat.vente.nbLots <= achat.choix.nombreLots) {
ChatUtility.removeChatMessageId(achat.chatMessageIdVente);
}
else if (achat.chatMessageIdVente) {
await ChatVente.diminuerQuantiteAchatVente(achat.chatMessageIdVente, achat.choix.nombreLots)
}
await this.updateMessageVente(achat.chatMessageIdVente, achat.choix.nombreLots);
}
}
async vendre(item, quantite, cout) {
await this.ajouterSols(cout);
await this.decrementerQuantiteItem(item, quantite);
async updateMessageVente(chatMessageIdVente, nombreLots) {
const chatMessage = game.messages.get(chatMessageIdVente)
if (!chatMessage.isOwner) {
return RdDBaseActor.remoteActorCall({
userId: Misc.firstConnectedGMId(),
actorId: this.id,
method: 'updateMessageVente', args: [chatMessageIdVente, nombreLots]
})
}
await ChatVente.diminuerQuantiteAchatVente(chatMessageIdVente, nombreLots);
}
async vendre(item, quantite, cout, acheteur) {
await this.ajouterSols(cout, acheteur?.id)
await this.decrementerQuantiteItem(item.id, quantite)
}
async acheter(item, quantite, cout, achat) {
await this.depenserSols(cout)
if (!this.isOwner) {
ui.notifications.warn(`${game.user.id} n'est pas propriétaire de ${this.name} et effectue un achat!`)
}
const createdItemId = await this.creerQuantiteItem(item, quantite)
if (achat.choix.consommer && item.type == 'nourritureboisson' && createdItemId != undefined) {
if (item.type == ITEM_TYPES.nourritureboisson && achat.choix.consommer && createdItemId != undefined) {
achat.choix.doses = achat.choix.nombreLots;
await this.consommerNourritureboisson(createdItemId, achat.choix, achat.vente.actingUserId);
}
if (item.type == ITEM_TYPES.service) {
new Apprecier(this, item.system.appreciation, item.system.qualite).apprecier()
}
}
verifierFortune(cout) {
@@ -533,43 +582,46 @@ export class RdDBaseActor extends Actor {
async consommerNourritureboisson(itemId, choix, userId) { }
async decrementerQuantiteItem(item, quantite, options = { supprimerSiZero: true }) {
async decrementerQuantiteItem(itemId, quantite, options = { supprimerSiZero: true }) {
const item = this.items.get(itemId)
if (item.isService()) {
return;
return
}
const itemId = item.id;
let resteQuantite = (item.system.quantite ?? 1) - quantite;
if (resteQuantite <= 0) {
if (options.supprimerSiZero) {
await this.deleteEmbeddedDocuments("Item", [item.id]);
}
else {
await this.updateEmbeddedDocuments("Item", [{ _id: itemId, 'system.quantite': 0 }]);
}
if (resteQuantite < 0) {
ui.notifications.warn(`La quantité de ${item.name} était insuffisante, l'objet a donc été supprimé`)
}
if (!this.isOwner) {
return RdDBaseActor.remoteActorCall({
userId: Misc.connectedGMOrUser(),
tokenId: this.token?.id,
actorId: this.id,
method: 'decrementerQuantiteItem', args: [itemId, quantite, options]
})
}
else if (resteQuantite > 0) {
const realItem = this.getItem(item.id)
realItem.update({ 'system.quantite': resteQuantite });
await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': resteQuantite }]);
const resteQuantite = Math.max((item.system.quantite ?? 1) - quantite, 0)
if (resteQuantite <= 0 && options.supprimerSiZero) {
await this.deleteEmbeddedDocuments("Item", [itemId]);
}
else {
await this.updateEmbeddedDocuments("Item", [{ _id: itemId, 'system.quantite': resteQuantite }])
}
}
async creerQuantiteItem(item, quantite) {
if (this.canReceive(item)) {
const isItemEmpilable = "quantite" in item.system;
const baseItem = {
type: item.type,
img: item.img,
name: item.name,
system: foundry.utils.mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined }, { inplace: false })
};
const newItems = isItemEmpilable ? [baseItem] : Array.from({ length: quantite }, (_, i) => baseItem);
const items = await this.createEmbeddedDocuments("Item", newItems);
return items.length > 0 ? items[0].id : undefined;
if (!this.canReceive(item)) {
return
}
const isItemEmpilable = "quantite" in item.system;
const baseItem = {
type: item.type,
img: item.img,
name: item.name,
system: foundry.utils.mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined }, { inplace: false })
}
const newItems = isItemEmpilable ? [baseItem] : Array.from({ length: quantite }, (_, i) => baseItem);
const items = await this.createEmbeddedDocuments("Item", newItems);
return newItems.length > 0 ? items[0].id : undefined;
}
/* -------------------------------------------- */
@@ -589,7 +641,7 @@ export class RdDBaseActor extends Actor {
}
getEncTotal() {
return Math.floor(this.encTotal ?? 0)
return Number(this.encTotal?.toFixed(2) ?? 0.00)
}
async createItem(type, name = undefined) {
@@ -622,7 +674,7 @@ export class RdDBaseActor extends Actor {
if (srcId != destId && itemId != destId) { // déplacement de l'objet
const src = this.getItem(srcId);
const dest = this.getItem(destId);
const cible = this.getContenantOrParent(dest);
const cible = this.findConteneurOrParent(dest);
const [empilable, message] = item.isInventaireEmpilable(dest);
if (empilable) {
await dest.empiler(item)
@@ -644,15 +696,15 @@ export class RdDBaseActor extends Actor {
return result;
}
getContenantOrParent(dest) {
findConteneurOrParent(dest) {
if (!dest || dest.isConteneur()) {
return dest;
}
return this.getContenant(dest);
return this.findConteneur(dest)
}
getContenant(item) {
return this.itemTypes['conteneur'].find(it => it.system.contenu.includes(item.id));
findConteneur(item) {
return this.itemTypes[ITEM_TYPES.conteneur].find(it => it.system.contenu.includes(item.id));
}
@@ -848,6 +900,7 @@ export class RdDBaseActor extends Actor {
listActionsPossessions() {
return this.itemTypes[ITEM_TYPES.possession]
.filter(it => !it.system.possede)
.map(p => {
return {
label: p.name,
@@ -856,9 +909,5 @@ export class RdDBaseActor extends Actor {
}
})
}
listActionsCombat() {
const possessions = this.listActionsPossessions()
return possessions.length > 0 ? possessions : this.listActions({})
}
}

View File

@@ -28,11 +28,11 @@ export class RdDCommerce extends RdDBaseActor {
await super.depenserSols(cout)
}
async decrementerQuantiteItem(item, quantite) {
async decrementerQuantiteItem(itemId, quantite) {
if (this.system.illimite) {
return;
}
await super.decrementerQuantiteItem(item, quantite, { supprimerSiZero: false });
await super.decrementerQuantiteItem(itemId, quantite, { supprimerSiZero: false });
}
calculerPrix(item) {

View File

@@ -19,8 +19,8 @@ export class RdDEntite extends RdDBaseActorReve {
isEntite() { return true }
isEntiteNonIncarnee() { return this.system.definition.typeentite == ENTITE_NONINCARNE }
isEntiteIncarnee() { return [ENTITE_INCARNE, ENTITE_BLURETTE].includes(this.system.definition.typeentite) }
isEntiteBlurette() { return this.system.definition.typeentite !== ENTITE_BLURETTE }
isEntiteIncarnee() { return !this.isEntiteNonIncarnee() }
isEntiteBlurette() { return this.system.definition.typeentite == ENTITE_BLURETTE }
getReveActuel() {
return Misc.toInt(this.system.carac.reve?.value)
@@ -41,13 +41,6 @@ export class RdDEntite extends RdDBaseActorReve {
getChance() { return this.getReve() }
getEnduranceMax() { return Math.max(1, this.getTaille() + this.getReve()) }
getDraconicOuPossession() {
return this.itemTypes[ITEM_TYPES.competencecreature]
.filter(it => it.system.categorie == 'possession')
.sort(Misc.descending(it => it.system.niveau))
.find(it => true);
}
async remiseANeuf() {
if (!this.isEntiteNonIncarnee()) {
await this.update({
@@ -108,6 +101,15 @@ export class RdDEntite extends RdDBaseActorReve {
return true
}
listActionsPossessions() {
if (this.isEntiteNonIncarnee()) {
return this.itemTypes[ITEM_TYPES.competencecreature]
.filter(it => it.system.ispossession)
.map(it => it.attaqueCreature())
.filter(it => it != undefined)
}
return super.listActionsPossessions()
}
/* -------------------------------------------- */
async setEntiteReveAccordee(actor) {
if (this.isEntiteIncarnee()) {

View File

@@ -3,6 +3,8 @@ import { RdDCarac } from "../../rdd-carac.js";
import { RdDItemCompetence } from "../../item-competence.js";
import { RdDUtility } from "../../rdd-utility.js";
import { TextRollManager } from "./text-roll-formatter.js";
import RollDialog from "../../roll/roll-dialog.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2 } from "../../settings/options-avancees.js";
const REGECP_CARAC = "(?<carac>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+)"
const REGEXP_COMP = "(\\/(?<competence>[A-Za-zÀ-ÖØ-öø-ÿ ]+([1-2]?[A-Za-zÀ-ÖØ-öø-ÿ ]+)?))?"
@@ -49,10 +51,11 @@ export class TextRollCaracCompetence {
caracCode = actor.mapCarac(caracCode)
if (caracCode) {
if (competence) {
await actor.rollCaracCompetence(caracCode, competence, diff)
await actor.rollCaracCompetence(caracCode, competence, diff,
{ title: "", onRollDone: RollDialog.onRollDoneClose })
}
else {
await actor.rollCarac(caracCode, { diff })
await actor.rollCarac(caracCode, { diff , onRollDone: RollDialog.onRollDoneClose})
}
}
}

View File

@@ -5,7 +5,7 @@ import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
/**
* Class providing helper methods to get the list of users, and
* Class providing helper methods around the Chat message
*/
export class ChatUtility {
@@ -76,6 +76,15 @@ export class ChatUtility {
ChatUtility.removeMessages({ part: part });
}
static remover(chatMessage) {
const messageId = chatMessage.id;
if (messageId) {
return (..._) => ChatUtility.removeMessages({ messageId: messageId });
}
return (..._) => { }
}
static removeChatMessageId(messageId) {
if (messageId) {
ChatUtility.removeMessages({ messageId: messageId });
@@ -206,11 +215,13 @@ export class ChatUtility {
static async onRenderChatMessage(chatMessage, html, data) {
const rddTimestamp = chatMessage.getFlag(SYSTEM_RDD, 'rdd-timestamp')
if (rddTimestamp) {
const heureRdD = $(html).find('header.message-header .heure-rdd')
if (rddTimestamp && heureRdD.length==0) {
const messageTimestamp = $(html).find('header.message-header .message-timestamp');
const timestamp = new RdDTimestamp(rddTimestamp);
const timestampData = timestamp.toCalendrier();
const dateHeure = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/common/date-heure.hbs', timestampData);
$(html).find('header.message-header .message-timestamp').after(dateHeure)
messageTimestamp.after(dateHeure)
}
}
@@ -224,4 +235,9 @@ export class ChatUtility {
static async setTimestamp(chatMessage) {
await chatMessage.setFlag(SYSTEM_RDD, 'rdd-timestamp', game.system.rdd.calendrier.getTimestamp());
}
static getISODate(chatMessage) {
const date = new Date(chatMessage.timestamp);
return date?.toISOString().substring(0, 10)
}
}

View File

@@ -0,0 +1,77 @@
import { ChatUtility } from "../chat-utility.js"
import { Misc } from "../misc.js"
import { RdDTimestamp } from "../time/rdd-timestamp.js"
const fields = foundry.applications.fields
export class DialogFlushByDate {
static async init() {
Hooks.once("renderChatLog", async () => await DialogFlushByDate.onFirstRenderChatLog())
}
static async onFirstRenderChatLog() {
if (game.user.isGM) {
const content = await foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat/button-flush-by-date.hbs')
const flushButton = document.querySelector("#chat-controls button[data-action='flush']")
flushButton.insertAdjacentHTML("afterend", content)
flushButton.parentElement.querySelector("button[name='flush-by-date']")?.addEventListener(
"click", e => {
if (game.messages.size > 0) {
DialogFlushByDate.create()
}
else {
ui.notifications.info("Aucun message à supprimer!")
}
e.preventDefault()
})
}
}
static async create() {
const dates = DialogFlushByDate.getChatMessageDates(game.messages)
const selectGroup = fields.createFormGroup({
input: fields.createSelectInput({
options: dates.map(it => { return { label: `${it.dateTerre} | ${it.dateReve}`, value: it.timestamp } }),
name: 'timestamp'
}),
label: 'Messages antérieurs au',
hint: 'Supprimer les messages antérieurs à la date'
})
const selected = await foundry.applications.api.DialogV2.input({
window: { title: "Supprimer les messages du tchat" },
content: selectGroup.outerHTML,
ok: {
label: "Supprimer",
icon: "fa-solid fa-trash-can",
}
})
if (selected) {
const timestamp = Number.parseInt(selected.timestamp)
const toDelete = game.messages.filter(it => it.timestamp < timestamp)
toDelete.forEach(it => it.delete())
}
}
static getChatMessageDates(messages) {
const datesTerre = Object.values(Misc.classifyFirst(messages,
m => ChatUtility.getISODate(m),
m => DialogFlushByDate.chatMessageDates(m)))
const timestamps = new Set(datesTerre.map(it => it.timestamp))
const datesReve = Object.values(Misc.classifyFirst(messages,
m => RdDTimestamp.fromChatMessage(m).isoDate(),
m => DialogFlushByDate.chatMessageDates(m)))
const dates = [...datesTerre, ...datesReve.filter(it => !timestamps.has(it.timestamp))]
return dates.sort(Misc.ascending(it => it.timestamp))
}
static chatMessageDates(it) {
return {
timestamp: it.timestamp,
dateTerre: new Date(it.timestamp).toLocaleDateString(),
dateReve: RdDTimestamp.fromChatMessage(it).formatDate()
}
}
}

View File

@@ -1,6 +1,7 @@
import { RdDBaseActor } from "../actor/base-actor.js";
import { ChatUtility } from "../chat-utility.js";
import { renderTemplate } from "../constants.js";
import { MORAL } from "../moral/apprecier.mjs";
const INFO_COEUR = 'info-coeur';
@@ -122,7 +123,7 @@ export class RdDCoeur {
const diff = Math.abs(infoCoeur.source.jetTendre - infoCoeur.target.jetTendre)
for (let amoureux of [infoCoeur.source, infoCoeur.target]) {
const actorAmoureux = game.actors.get(amoureux.actor.id);
amoureux.situation = diff <= amoureux.coeur ? 'heureux' : 'neutre'
amoureux.situation = diff <= amoureux.coeur ? MORAL.HEUREUX : MORAL.NEUTRE
amoureux.gainMoral = await actorAmoureux.jetDeMoral(amoureux.situation)
}
const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-accepter-tendre-moment.hbs`, infoCoeur)

122
module/combat/distance.mjs Normal file
View File

@@ -0,0 +1,122 @@
import { ITEM_TYPES } from "../constants.js"
import { Grammar } from "../grammar.js"
import { ATTAQUE_TYPE } from "../item/arme.js"
import { Misc } from "../misc.js"
export class Distance {
static typeAttaqueDistance(attaque) {
function mapTypeAttaque(value) {
switch (value) {
case ATTAQUE_TYPE.LANCER: case 'lancer': return ATTAQUE_TYPE.LANCER
case ATTAQUE_TYPE.TIR: case 'tir': return ATTAQUE_TYPE.TIR
}
return undefined
}
switch (attaque.comp?.type) {
case ITEM_TYPES.competence: return mapTypeAttaque(attaque.main)
case ITEM_TYPES.competencecreature: return mapTypeAttaque(attaque.arme.system.categorie)
}
return undefined
}
static ajustements(token, defenderToken, attaque) {
const typeAttaque = Distance.typeAttaqueDistance(attaque)
if (typeAttaque) {
const distance = Distance.distance(token, defenderToken)
const isVisible = Distance.isVisible(token, defenderToken)
const portee = Distance.ajustementPortee(distance, attaque.arme)
const taille = Distance.ajustementTaille(defenderToken?.actor)
const activite = Distance.ajustementMouvement(defenderToken)
const total = Distance.diff(portee, taille, activite)
const diffDefense = Distance.ajustementDefense(attaque)
return { typeAttaque, isVisible, distance, portee, taille, activite, total, diffDefense }
}
return undefined
}
static distance(token, defenderToken) {
if (Distance.$isToken(token) && Distance.$isToken(defenderToken)) {
const source = token.getCenterPoint()
const target = defenderToken.getCenterPoint()
const measure = canvas.grid.measurePath([ source, target])
return measure.distance
}
return -1 /* distance indéterminée */
}
static isVisible(token, defenderToken) {
// TODO: regarder les StatusEffect aveuglé?
if (Distance.$isToken(token) && Distance.$isToken(defenderToken)) {
return canvas.effects.visibility.testVisibility(defenderToken.getCenterPoint(), { object: token })
}
return true
}
static ajustementPortee(distance, arme) {
if (distance < 0 || !arme) {
return { msg: "non déterminée", diff: 0 };
}
if (arme.system.portee_courte && distance <= arme.system.portee_courte) return { msg: "courte", diff: 0 };
if (arme.system.portee_moyenne && distance <= arme.system.portee_moyenne) return { msg: "moyenne", diff: -3 };
if (arme.system.portee_extreme && distance <= arme.system.portee_extreme) return { msg: "extrême", diff: -5 };
return { msg: "inatteignable", diff: -10 };
}
static ajustementTaille(actor) {
if (!actor) {
return { msg: "non déterminée", diff: 0 };
}
if (actor.isVehicule()) return { msg: "véhicule", diff: 0 }
const taille = actor.getCaracByName('TAILLE')?.value ?? 1;
if (taille <= 1) return { msg: "souris", diff: -8 };
if (taille <= 3) return { msg: "chat", diff: -4 };
if (taille <= 5) return { msg: "chien", diff: -2 };
if (taille <= 15) return { msg: "humanoïde", diff: 0 };
if (taille <= 20) return { msg: "ogre", diff: 2 };
return { msg: "gigantesque", diff: 4 };
}
static ajustementMouvement(defenderToken) {
if (Distance.$isToken(defenderToken)) {
if (defenderToken.actor?.getSurprise(true) != '') return { msg: "immobile (surprise)", diff: 0 };
if (defenderToken.inCombat) return { msg: "en combat", diff: -4 };
}
return { msg: "à déterminer", diff: -3 };
}
static diff(...ajustements) {
return ajustements.map(it => it.diff).filter(d => !Number.isNaN(d)).reduce(Misc.sum(), 0)
}
static ajustementDefense(attaque) {
switch (Grammar.toLowerCaseNoAccentNoSpace(attaque.comp.name)) {
case 'arbalete': return { label: 'Parade carreau', value: -5 }
case 'arc': return { label: 'Parade flêche', value: -5 }
case 'fronde': return { label: 'Parade bille de fronde', value: -4 }
case 'daguedejet': return { label: 'Parade/Esquive dague lancée', value: -2 }
case 'javelot': return { label: 'Parade/Esquive javelot lancé', value: -2 }
case 'fouet': return { label: 'Parade/Esquive fouet', value: 0 }
}
return { label: 'Parade/esquive projectile', value: 0 }
}
static ajustementBouclier(bouclier) {
if (bouclier?.system.categorie_parade == 'boucliers') {
if (bouclier.system.force < 10) {
return { label: 'Bouclier léger', value: -3 }
}
if (bouclier.system.force < 12) {
return { label: 'Bouclier moyen', value: 0 }
}
return { label: 'Bouclier lourd', value: 3 }
}
/* esquive */
return undefined
}
static $isToken(token) {
return token instanceof Token || token instanceof TokenDocument
}
}

View File

@@ -7,7 +7,7 @@ const fields = foundry.data.fields
export class CommonInventaire extends CommonTemplate {
fields() {
return {
encombrement: new fields.NumberField({ label: "Encombrement", initial: 0, ...INTEGER }),
encombrement: new fields.NumberField({ label: "Encombrement", initial: 0, ...DECIMAL }),
quantite: new fields.NumberField({ label: "Quantité", initial: 1, ...INTEGER }),
qualite: new fields.NumberField({ label: "Qualité", initial: 0, ...INTEGER_SIGNED }),
cout: new fields.NumberField({ label: "Coût", initial: 0.0, ...DECIMAL }),

View File

@@ -61,6 +61,7 @@ export const RDD_CONFIG = {
armesDisparates: 'systems/foundryvtt-reve-de-dragon/assets/actions/armes-disparates.svg',
demiReve: 'systems/foundryvtt-reve-de-dragon/assets/actions/sort.svg',
empoignade: 'systems/foundryvtt-reve-de-dragon/assets/actions/empoignade.svg',
possession: 'systems/foundryvtt-reve-de-dragon/assets/actions/possession.svg',
forceWeak: 'systems/foundryvtt-reve-de-dragon/assets/actions/weak.svg',
surenc: 'systems/foundryvtt-reve-de-dragon/assets/actions/surenc.svg',
magique: 'systems/foundryvtt-reve-de-dragon/assets/actions/magique.svg',

View File

@@ -70,7 +70,7 @@ export class DialogChronologie extends Dialog {
async ajouter() {
await this.forceValidation();
const { journalId, journalEntry } = this.findJournal();
if (journalEntry?.canUserModify(game.user)) {
if (journalEntry?.canUserModify(game.user, 'update')) {
const journalParameters = this.extractJournalParameters();
const jour = journalParameters.dateRdD.jour;

View File

@@ -3,6 +3,7 @@ import { renderTemplate } from "./constants.js"
export class DialogSelect extends Dialog {
static extractIdNameImg(it) { return { id: it.id, name: it.name, img: it.img } }
static async select(selectionData, onSelectChoice) {
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-select.hbs", selectionData)

View File

@@ -1,10 +1,10 @@
import { ITEM_TYPES, renderTemplate } from "../constants.js"
import { ACTOR_TYPES, ITEM_TYPES, renderTemplate } from "../constants.js"
import { RdDItemSort } from "../item-sort.js"
import { Misc } from "../misc.js"
export const ACTION_ITEM_ENCHANTER = {
code: 'item-enchanter', label: 'Enchanter', icon: it => 'fa-solid fa-sparkles',
filter: it => game.user.isGM || DialogEnchanter.isEnchantable(it) && it.parent?.type != ACTOR_TYPES.commerce,
filter: it => DialogEnchanter.isEnchantable(it) && it.parent?.type != ACTOR_TYPES.commerce,
action: (item, actor) => DialogEnchanter.enchanter(item)
}

View File

@@ -2,7 +2,7 @@
import { Grammar } from "./grammar.js";
import { RdDInitiative } from "./initiative.mjs";
import { RdDItem } from "./item.js";
import { CATEGORIES_COMPETENCE_COMBAT, CATEGORIES_COMPETENCES, SANS_COMPETENCE } from "./item/base-items.js";
import { CATEGORIES_COMPETENCES, SANS_COMPETENCE } from "./item/base-items.js";
import { Misc } from "./misc.js";
const competenceTroncs = [["Esquive", "Dague", "Corps à corps"],
@@ -136,7 +136,7 @@ export class RdDItemCompetence extends RdDItem {
return troncList;
}
}
return [];
return []
}
/* -------------------------------------------- */

View File

@@ -2,6 +2,7 @@ import { ITEM_TYPES } from "./constants.js";
import { RdDItem } from "./item.js";
import { RdDInitiative } from "./initiative.mjs";
import { RdDItemArme } from "./item/arme.js";
import { Distance } from "./combat/distance.mjs";
/* -------------------------------------------- */
export class RdDItemCompetenceCreature extends RdDItem {
@@ -45,12 +46,12 @@ export class RdDItemCompetenceCreature extends RdDItem {
equipe: true,
mortalite: this.system.mortalite,
dommages: this.system.dommages,
//dmg: this.system.dommages,
initiative: initative
};
}
attaque.isDistance = Distance.typeAttaqueDistance(attaque)
return attaque
}
return undefined;
return undefined
}
getCategorieAttaque() {

View File

@@ -14,6 +14,9 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js";
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
import { ItemAction } from "./item/item-actions.js";
import { SANS_COMPETENCE } from "./item/base-items.js";
import { Apprecier } from "./moral/apprecier.mjs";
import { CARACS } from "./rdd-carac.js";
/**
* Extend the basic ItemSheet for RdD specific items
@@ -89,6 +92,7 @@ export class RdDItemSheetV1 extends foundry.appv1.sheets.ItemSheet {
/* -------------------------------------------- */
async getData() {
const competences = (await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage))
let formData = {
title: this.item.name,
id: this.item.id,
@@ -101,8 +105,9 @@ export class RdDItemSheetV1 extends foundry.appv1.sheets.ItemSheet {
descriptionmj: await RdDTextEditor.enrichHTML(this.item.system.descriptionmj, this.item),
isComestible: this.item.getUtilisationCuisine(),
options: RdDSheetUtility.mergeDocumentRights({}, this.item, this.isEditable),
competences: await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage),
competences: [new RdDItemCompetence(SANS_COMPETENCE), ...competences],
categories: RdDItem.getCategories(this.item.type),
isAppreciable: Apprecier.isAppreciable(this.item)
}
if (this.item.type == ITEM_TYPES.competencecreature) {
@@ -114,7 +119,7 @@ export class RdDItemSheetV1 extends foundry.appv1.sheets.ItemSheet {
this.item.type == ITEM_TYPES.meditation ||
this.item.type == ITEM_TYPES.oeuvre) {
formData.caracList = foundry.utils.duplicate(game.model.Actor.personnage.carac)
formData.caracList["reve-actuel"] = foundry.utils.duplicate(game.model.Actor.personnage.reve.reve)
formData.caracList[CARACS.REVE_ACTUEL] = foundry.utils.duplicate(game.model.Actor.personnage.reve.reve)
}
if (this.item.type == ITEM_TYPES.arme) {
formData.competences = formData.competences.filter(it => it.isCompetenceArme())

View File

@@ -3,6 +3,7 @@ import { RdDItemCompetence } from "./item-competence.js";
import { ITEM_TYPES } from "./constants.js";
import { Misc } from "./misc.js";
import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js";
import { RdDItem } from "./item.js";
export const VOIES_DRACONIC = [
{ code: 'O', label: "Voie d'Oniros", short: 'Oniros', ordre: 'a' },
@@ -14,7 +15,7 @@ export const VOIES_DRACONIC = [
]
/* -------------------------------------------- */
export class RdDItemSort extends Item {
export class RdDItemSort extends RdDItem {
static preloadHandlebars() {
Handlebars.registerHelper('itemSort-codeDraconic', voie => RdDItemSort.getCode(voie))
Handlebars.registerHelper('itemSort-shortDraconic', voie => RdDItemSort.getShortVoie(voie))
@@ -40,6 +41,11 @@ export class RdDItemSort extends Item {
return value ? value.replace('variable', 'var') : ''
}
static computeTotalXP(sorts) {
return sorts.map(sort => RdDItemSort.isDifficulteVariable(sort) ? 70 : -10 * Misc.toInt(sort.system.difficulte))
.reduce(Misc.sum(), 0)
}
static isSortOnCoord(sort, coord) {
let tmr = TMRUtility.getTMR(coord)
const caseTMR = sort.system.caseTMR.toLowerCase();
@@ -62,7 +68,7 @@ export class RdDItemSort extends Item {
static diffReve(sort) { return RdDItemSort.toVar((sort.system.difficulte.match(/\-?(\d)+/) ? 'R' : 'R ') + sort.system.difficulte) }
static coutReve(sort) { return RdDItemSort.toVar((Number.isInteger(sort.system.ptreve || sort.system.ptreve.match(/(\d)+\+?/)) ? 'r' : 'r ') + sort.system.ptreve) }
static coutReve(sort) { return RdDItemSort.toVar((Number.isInteger(sort.system.ptreve) || sort.system.ptreve.match(/(\d)+\+?/) ? 'r' : 'r ') + sort.system.ptreve) }
static getDraconicsSort(competencesDraconic, sort) {
// se baser sur la voie du sort?
switch (Grammar.toLowerCaseNoAccent(sort.name)) {

View File

@@ -28,7 +28,7 @@ const typesInventaireMateriel = [
]
const typesInventaire = {
materiel: typesInventaireMateriel,
all: ['service'].concat(typesInventaireMateriel),
all: [ITEM_TYPES.service].concat(typesInventaireMateriel),
}
const typesObjetsOeuvres = [ITEM_TYPES.oeuvre, ITEM_TYPES.recettecuisine, ITEM_TYPES.musique, ITEM_TYPES.chant, ITEM_TYPES.danse, ITEM_TYPES.jeu]
@@ -36,6 +36,10 @@ const typesObjetsDraconiques = [ITEM_TYPES.queue, ITEM_TYPES.ombre, ITEM_TYPES.s
const typesObjetsConnaissance = [ITEM_TYPES.meditation, ITEM_TYPES.recettealchimique, ITEM_TYPES.sort]
const typesObjetsEffet = [ITEM_TYPES.possession, ITEM_TYPES.poison, ITEM_TYPES.maladie, ITEM_TYPES.blessure]
const typesObjetsCompetence = [ITEM_TYPES.competence, ITEM_TYPES.competencecreature]
const typesAppreciable = [
ITEM_TYPES.oeuvre, ITEM_TYPES.musique, ITEM_TYPES.chant, ITEM_TYPES.danse, ITEM_TYPES.nourritureboisson,
ITEM_TYPES.jeu, ITEM_TYPES.service
]
const typesObjetsTemporels = [ITEM_TYPES.blessure, ITEM_TYPES.poison, ITEM_TYPES.maladie, ITEM_TYPES.queue, ITEM_TYPES.ombre, ITEM_TYPES.souffle, ITEM_TYPES.signedraconique, ITEM_TYPES.rencontre]
const typesObjetsEquipable = [ITEM_TYPES.arme, ITEM_TYPES.armure, ITEM_TYPES.objet];
const typesEnvironnement = typesInventaireMateriel;
@@ -77,13 +81,13 @@ export const defaultItemImg = {
souffle: "systems/foundryvtt-reve-de-dragon/icons/souffle_dragon.webp",
tarot: "systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.webp",
tete: "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp",
monnaie:"systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp",
monnaie: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp",
munition: "systems/foundryvtt-reve-de-dragon/icons/objets/fleche.webp"
}
/* -------------------------------------------- */
export class RdDItem extends Item {
static get defaultIcon() {
return undefined;
}
@@ -96,14 +100,14 @@ export class RdDItem extends Item {
switch (field) {
case 'quantite':
if (ITEM_TYPES.conteneur == type) {
return false;
return false
}
break;
case 'cout':
if (ITEM_TYPES.monnaie == type) {
return game.user.isGM;
}
break;
break
}
return true;
}
@@ -180,10 +184,17 @@ export class RdDItem extends Item {
isCompetencePersonnage() { return this.type == ITEM_TYPES.competence }
isCompetenceCreature() { return this.type == ITEM_TYPES.competencecreature }
isConteneur() { return this.type == ITEM_TYPES.conteneur; }
isMonnaie() { return this.type == ITEM_TYPES.monnaie; }
isConteneur() { return this.type == ITEM_TYPES.conteneur }
findConteneur() {
if (this.isInventaire('all') && this.parent) {
return this.parent.findConteneur(this)
}
return undefined
}
isMonnaie() { return this.type == ITEM_TYPES.monnaie }
isNourritureBoisson() { return this.type == ITEM_TYPES.nourritureboisson; }
isService() { return this.type == ITEM_TYPES.service; }
isService() { return this.type == ITEM_TYPES.service }
isAttaque() { return false }
isParade() { return false }
isBouclier() { return false }
@@ -205,7 +216,7 @@ export class RdDItem extends Item {
return this.isCompetence() && ['melee', 'tir', 'lancer'].includes(this.system.categorie)
}
isCompetencePossession() { return ITEM_TYPES.competencecreature == this.type && this.system.categorie == "possession" }
isCompetencePossession() { return ITEM_TYPES.competencecreature == this.type && this.system.categorie == CATEGORIES_COMPETENCES_CREATURES.possession.key }
isTemporel() { return typesObjetsTemporels.includes(this.type) }
isOeuvre() { return typesObjetsOeuvres.includes(this.type) }
isDraconique() { return RdDItem.getItemTypesDraconiques().includes(this.type) }
@@ -214,6 +225,7 @@ export class RdDItem extends Item {
isConnaissance() { return typesObjetsConnaissance.includes(this.type) }
isInventaire(mode = 'materiel') { return RdDItem.getItemTypesInventaire(mode).includes(this.type); }
isAppreciable() { return typesAppreciable.includes(this.type) }
isBoisson() { return this.isNourritureBoisson() && this.system.boisson; }
isAlcool() { return this.isNourritureBoisson() && this.system.boisson && this.system.alcoolise; }
isHerbeAPotion() { return this.type == ITEM_TYPES.herbe && (this.system.categorie == 'Soin' || this.system.categorie == 'Repos'); }
@@ -364,11 +376,11 @@ export class RdDItem extends Item {
getEnc() {
switch (this.type) {
case ITEM_TYPES.service:
return 0;
return 0
case ITEM_TYPES.herbe:
return this.getEncHerbe();
return this.getEncHerbe()
}
return Math.max(this.system.encombrement ?? 0, 0);
return Math.max(this.system.encombrement ?? 0.0, 0.0);
}
getEncContenu() {
@@ -384,9 +396,9 @@ export class RdDItem extends Item {
getEncHerbe() {
switch (this.system.categorie) {
case 'Repos': case 'Soin': case 'Alchimie':
return encBrin;
return encBrin
}
return this.system.encombrement;
return this.system.encombrement
}

View File

@@ -45,7 +45,7 @@ export class RdDItemArme extends RdDItem {
isParade() { return this.system.resistance > 0 && this.system.categorie_parade }
isBouclier() { return RdDItemArme.getCategorieParade(this).includes('bouclier') }
getCompetenceAction(main) {
switch (main) {
case ATTAQUE_TYPE.UNE_MAIN: return this.competence1Mains()
@@ -174,24 +174,30 @@ export class RdDItemArme extends RdDItem {
static defenseArmeParade(armeAttaque, armeParade) {
const defCategory = RdDItemArme.getCategorieParade(armeParade)
if (defCategory == 'boucliers') {
return 'norm'
switch (defCategory) {
case 'boucliers':
return 'norm'
case '':
return 'impossible'
}
if (armeAttaque?.system?.competence?.toLowerCase().match(/(fléau)/)) {
return ''
}
if (armeParade.system?.tir) {
return ''
if (RdDItemArme.$isFleau(armeAttaque)) {
return 'impossible'
}
const attCategory = RdDItemArme.getCategorieParade(armeAttaque)
switch (attCategory) {
case 'armes-naturelles': case 'sans-armes':
return defCategory == 'sans-armes' ? 'norm' : ''
case 'sans-armes':
case 'armes-naturelles':
return defCategory == attCategory ? 'norm' : 'impossible'
default:
return RdDItemArme.needParadeSignificative(armeAttaque, armeParade) ? 'sign' : 'norm'
}
}
static $isFleau(armeAttaque) {
return armeAttaque?.system?.competence?.toLowerCase().match(/(fléau)/);
}
/* -------------------------------------------- */
static needParadeSignificative(armeAttaque, armeParade) {
if (!armeAttaque || !armeParade) {
@@ -278,6 +284,10 @@ export class RdDItemArme extends RdDItem {
return this.system.mortalite == RDD_CONFIG.encaissement.empoignade
}
isPossession() {
return this.system.mortalite == RDD_CONFIG.encaissement.possession
}
isUtilisableEmpoigne() {
return this.system.baseInit == 3 || this.system.baseInit == 4 || this.system.competence == "Dague"
}

View File

@@ -1,22 +1,5 @@
export const POSSESSION_SANS_DRACONIC = { name: 'Sans draconic', type: 'competence', system: { niveau: 0, defaut_carac: "reve-actuel", }, img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp' }
export const PAS_DE_DRACONIC = { name: 'Pas de draconic', type: 'competence', system: { niveau: -11, defaut_carac: "reve" }, img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp' }
export const BASE_CORPS_A_CORPS = { name: 'Corps à Corps', type: 'competence', system: { niveau: -6, defaut_carac: "melee" }, img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp' }
export const BASE_ESQUIVE = { name: 'Esquive', type: 'competence', system: { niveau: -6, defaut_carac: "derobee" }, img: 'systems/foundryvtt-reve-de-dragon/icons/competence_esquive.webp' }
export const SANS_COMPETENCE = {
name: "Sans compétence",
type: 'competence',
system: {
niveau: 0,
default_diffLibre: 0,
base: 0,
categorie: "Aucune",
description: "",
descriptionmj: "",
defaut_carac: "",
},
img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp"
}
import { ITEM_TYPES, RDD_CONFIG } from "../constants.js"
import { CARACS } from "../rdd-carac.js"
export const CATEGORIES_COMPETENCES = {
generale: { key: 'generale', base: -4, label: "Générales" },
@@ -39,3 +22,25 @@ export const CATEGORIES_COMPETENCES_CREATURES = {
lancer: { key: 'lancer', base: 0, label: "Lancer" },
possession: { key: 'possession', base: 0, label: "Possession" },
}
export const POSSESSION_SANS_DRACONIC = {
name: 'Sans draconic',
type: ITEM_TYPES.competence,
img: RDD_CONFIG.icons.possession,
system: { niveau: 0, defaut_carac: CARACS.REVE_ACTUEL, categorie: CATEGORIES_COMPETENCES.draconic.key }
}
export const PAS_DE_DRACONIC = { name: 'Pas de draconic', type: 'competence', system: { niveau: -11, defaut_carac: "reve" }, img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp' }
export const BASE_CORPS_A_CORPS = { name: 'Corps à Corps', type: 'competence', system: { niveau: -6, defaut_carac: "melee" }, img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp' }
export const BASE_ESQUIVE = { name: 'Esquive', type: 'competence', system: { niveau: -6, defaut_carac: "derobee" }, img: 'systems/foundryvtt-reve-de-dragon/icons/competence_esquive.webp' }
export const SANS_COMPETENCE = {
name: "Sans compétence",
type: ITEM_TYPES.competence,
img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp",
system: {
niveau: 0,
default_diffLibre: 0,
categorie: CATEGORIES_COMPETENCES.generale.key,
}
}

View File

@@ -1,4 +1,4 @@
import { ACTOR_TYPES } from "../constants.js"
import { ACTOR_TYPES, ITEM_TYPES } from "../constants.js"
import { Misc } from "../misc.js"
import { RdDSheetUtility } from "../rdd-sheet-utility.js"
import { RdDUtility } from "../rdd-utility.js"
@@ -11,33 +11,35 @@ import { RdDUtility } from "../rdd-utility.js"
const _SPACEHOLDER = { placeholder: true }
const _VENDRE = {
code: 'item-vendre', label: 'Vendre ou donner', icon: it => 'fa-solid fa-comments-dollar',
code: 'item-vendre', label: 'Vendre ou donner', icon: 'fa-solid fa-comments-dollar',
filter: it => Misc.toInt(it.system.quantite) > 0 || it.parent?.type == ACTOR_TYPES.commerce,
action: (item, actor) => item.proposerVente()
}
const _ACHETER = {
code: 'item-acheter', label: 'Acheter', icon: it => 'fa-regular fa-coins',
code: 'item-acheter', label: 'Acheter', icon: 'fa-regular fa-coins',
filter: it => it.parent?.type == ACTOR_TYPES.commerce,
allowLimited: true,
action: (item, actor) => actor.vente(item)
}
const _MONTRER = {
code: 'item-montrer', label: 'Montrer', icon: it => 'fa-solid fa-comment',
code: 'item-montrer', label: 'Montrer', icon: 'fa-solid fa-comment',
allowLimited: true,
action: (item, actor) => item.postItemToChat()
}
const _SPLIT = {
code: 'item-split', label: 'Séparer le goupe', icon: it => 'fa-solid fa-unlink',
code: 'item-split', label: 'Séparer le goupe', icon: 'fa-solid fa-unlink',
filter: it => Misc.toInt(it.system.quantite) > 1 && it.parent?.type != ACTOR_TYPES.commerce,
action: (item, actor) => RdDSheetUtility.splitItem(item, actor)
}
const _EDIT = {
code: 'item-edit', label: 'Editer', icon: it => 'fa-solid fa-edit',
code: 'item-edit', label: it => it.type == ITEM_TYPES.conteneur ? 'Ouvrir' : 'Editer',
icon: 'fa-solid fa-edit',
action: (item, actor) => item.sheet.render(true)
}
const _DELETE = {
code: 'item-delete', label: 'Supprimer', icon: it => 'fa-solid fa-trash',
code: 'item-delete', label: 'Supprimer', icon: 'fa-solid fa-trash',
optionsFilter: options => options.isOwner,
action: (item, actor) => RdDUtility.confirmActorItemDelete(item, actor)
}
@@ -48,53 +50,55 @@ const _EQUIPER = {
}
const _CUISINER = {
code: 'item-cuisiner', label: 'Cuisiner', icon: it => 'fa-solid fa-utensils',
code: 'item-cuisiner', label: 'Cuisiner',
img: 'systems/foundryvtt-reve-de-dragon/assets/actions/cuisine.svg',
filter: it => it.getUtilisation() == 'cuisine' && it.system.sust > 0,
action: (item, actor) => actor.preparerNourriture(item)
}
const _MANGER_CRU = {
code: 'item-manger-cru', label: 'Manger cru', icon: it => 'fa-solid fa-drumstick-bite',
code: 'item-manger-cru', label: 'Manger cru', icon: 'fa-solid fa-drumstick-bite',
filter: it => it.getUtilisation() == 'cuisine' && it.system.sust > 0,
action: (item, actor) => actor.mangerNourriture(item)
}
const _MANGER = {
code: 'item-manger', label: 'Manger', icon: it => 'fa-solid fa-utensils',
code: 'item-manger', label: 'Manger', icon: 'fa-solid fa-utensils',
filter: it => !(it.system.boisson),
action: (item, actor) => actor.mangerNourriture(item)
}
const _BOIRE = {
code: 'item-boire', label: 'Boire', icon: it => 'fa-solid fa-glass-water',
code: 'item-boire', label: 'Boire', icon: 'fa-solid fa-glass-water',
filter: it => it.system.boisson,
action: (item, actor) => actor.mangerNourriture(item)
}
const _DECOCTION = {
code: 'item-decoction', label: 'Décoction', icon: it => 'fa-solid fa-flask-vial',
code: 'item-decoction', label: 'Décoction', icon: 'fa-solid fa-flask-vial',
action: (item, actor) => actor.fabriquerDecoctionHerbe(item)
}
const _OUVRIR = {
code: 'item-edit', label: 'Ouvrir', icon: it => 'fa-solid fa-eye',
code: 'item-edit', label: 'Ouvrir',
img: 'systems/foundryvtt-reve-de-dragon/assets/actions/ouvrir.svg',
action: (item, actor) => item.sheet.render(true)
}
const _LIRE = {
code: 'item-lire', label: 'Lire', icon: it => 'fa-solid fa-book-open',
code: 'item-lire', label: 'Lire', icon: 'fa-solid fa-book-open',
action: (item, actor) => actor.actionLire(item)
}
const _REFOULER = {
code: 'item-refouler', label: 'Refouler', icon: it => 'fa-solid fa-burst',
code: 'item-refouler', label: 'Refouler', icon: 'fa-solid fa-burst',
filter: it => it.system.refoulement > 0,
action: (item, actor) => actor.actionRefoulement(item)
}
const _SORT_RESERVE = {
code: 'item-sortreserve-add', label: 'Ajouter en réserve', icon: it => 'fa-solid fa-sparkles',
code: 'item-sortreserve-add', label: 'Ajouter en réserve', icon: 'fa-solid fa-sparkles',
filter: it => game.user.isGM && !it.system.isrituel,
action: (item, actor) => actor.addSortReserve(item)
}
export const COMMON_ACTIONS = [_EQUIPER]
export const DEFAULT_ACTIONS = [_ACHETER, _SPACEHOLDER, _SPLIT, _VENDRE, _MONTRER, _EDIT, _DELETE]
export const DEFAULT_ACTIONS = [_ACHETER, _SPLIT, _SPACEHOLDER, _VENDRE, _MONTRER, _EDIT, _DELETE]
export const ITEM_ACTIONS = {
faune: [_CUISINER, _MANGER_CRU],
@@ -119,11 +123,31 @@ export class ItemAction {
&& (!action.optionsFilter || action.optionsFilter(options))
}
static icon(action, item) {
if (action && action.icon) {
return action.icon(item)
static label(action, item) {
if (action.placeholder) {
return ""
}
return undefined
return ItemAction.getParam(action.label, item)
}
static img(action, item) {
if (action.placeholder) {
return ""
}
const img = ItemAction.getParam(action.img, item)
if (img) {
return `<img src="${img}" />`
}
const icon = ItemAction.getParam(action.icon, item)
if (icon) {
return `<i class="${icon}"></i>`
}
return action.label
}
static getParam(p, item) {
return typeof (p) == 'function' ? p(item) : p
}
static async onActionItem(event, actor, options) {

View File

@@ -76,7 +76,7 @@ export class RdDItemRace extends RdDItem {
ui.notifications.warn("La Taille est inférieur au minimum racial")
return min
}
const raceMax = this.system.carac.taille.max;
const raceMax = this.system.carac.taille.max == undefined ? 15 + this.system.carac.taille.value : this.system.carac.taille.max
const max = raceMax < 0 ? taille + 1 : raceMax
if (max < taille) {
ui.notifications.warn("La Taille est supérieure au maximum racial")

View File

@@ -8,6 +8,7 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDRaretes } from "./item/raretes.js";
import { VOIES_DRACONIC } from "./item-sort.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { APPRECIATION } from "./moral/apprecier.mjs";
class Migration {
get code() { return "sample"; }
@@ -33,7 +34,6 @@ class Migration {
await Item.updateDocuments(itemUpdates);
}
}
}
class _1_5_34_migrationPngWebp {
@@ -662,6 +662,57 @@ class _13_0_7_FixNiveauOeuvres extends Migration {
}
}
class _13_0_21_AjoutAppreciation extends Migration {
get code() { return "ajout-appreciation" }
get version() { return "13.0.21" }
async migrate() {
await this.applyItemsUpdates(items => items
.filter(it => it.isAppreciable())
.filter(it => this.getBaseAppreciation(it))
.map(it => {
return { _id: it.id, 'system.appreciation': this.getBaseAppreciation(it) }
})
)
}
getBaseAppreciation(item) {
switch (item.type) {
case ITEM_TYPES.nourritureboisson: return APPRECIATION.CUISINE
case ITEM_TYPES.service: return APPRECIATION.SERVICE
case ITEM_TYPES.musique: return APPRECIATION.MUSIQUE
case ITEM_TYPES.chant: return APPRECIATION.CHANT
case ITEM_TYPES.danse: return APPRECIATION.DANSE
case ITEM_TYPES.oeuvre: {
const appreciation = foundry.utils.duplicate(APPRECIATION.OEUVRE)
appreciation.competence = item.system.competence
return appreciation
}
}
return undefined
}
}
class _13_0_22_PoidsDesMonnaies extends Migration {
get code() { return "poid-monnaies" }
get version() { return "13.0.22" }
async migrate() {
await this.applyItemsUpdates(items => items
.filter(it => it.type == ITEM_TYPES.monnaie)
.map(it => {
return { _id: it.id, 'system.encombrement': this.poids(it) }
})
)
}
poids(monnaie) {
if (monnaie.system.cout < 0.05) return 0.001
if (monnaie.system.cout < 0.5) return 0.002
if (monnaie.system.cout < 5) return 0.003
return 0.004
}
}
export class Migrations {
static getMigrations() {
return [
@@ -687,6 +738,8 @@ export class Migrations {
new _12_0_38_TachesEcriture(),
new _13_0_4_FixReveActuel(),
new _13_0_7_FixNiveauOeuvres(),
new _13_0_21_AjoutAppreciation(),
new _13_0_22_PoidsDesMonnaies(),
];
}
@@ -707,7 +760,10 @@ export class Migrations {
}
if (foundry.utils.isNewerVersion(game.system.version, currentVersion)) {
// if (true) { /* comment previous and uncomment here to test before upgrade */
const migrations = Migrations.getMigrations().filter(m => foundry.utils.isNewerVersion(m.version, currentVersion));
const migrations = Migrations.getMigrations().filter(m => foundry.utils.isNewerVersion(m.version, currentVersion)
/* uncomment and set the version to migrate to to force a migration */
// ||m.version == "13.0.21"
)
if (migrations.length > 0) {
migrations.sort((a, b) => this.compareVersions(a, b));
migrations.forEach(async (m) => {

View File

@@ -134,12 +134,12 @@ export class Misc {
return itemsBy
}
static classifyFirst(items, classifier) {
static classifyFirst(items, classifier, classified = it => it) {
let itemsBy = {};
for (const item of items) {
const classification = classifier(item);
if (!itemsBy[classification]) {
itemsBy[classification] = item;
itemsBy[classification] = classified(item);
}
}
return itemsBy;
@@ -180,11 +180,15 @@ export class Misc {
return (a, b) => a + separator + b;
}
static connectedGMOrUser(ownerId = undefined) {
if (ownerId && game.user.id == ownerId) {
return ownerId;
static connectedUserOrGM(userId = undefined) {
if (userId && game.user.id == userId) {
return userId
}
return Misc.firstConnectedGM()?.id ?? game.user.id;
return Misc.firstConnectedGM()?.id
}
static connectedGMOrUser(userId = undefined) {
return Misc.connectedUserOrGM(userId) ?? game.user.id
}
static isRollModeHiddenToPlayer() {
@@ -200,10 +204,7 @@ export class Misc {
}
static firstConnectedGM() {
if (foundry.utils.isNewerVersion(game.release.version, '12.0')) {
return game.users.activeGM
}
return game.users.find(u => u.isGM && u.active);
return game.users.activeGM
}
static connectedGMs() {
@@ -224,7 +225,9 @@ export class Misc {
*/
static documentIfResponsible(document) {
if (Misc.isFirstConnectedGM() || (Misc.connectedGMs().length == 0 && Misc.isFirstOwnerPlayer(document))) {
return document
if (document.isOwner) {
return document
}
}
return undefined
}
@@ -233,16 +236,16 @@ export class Misc {
if (Misc.isOwnerPlayer(document)) {
return await action(document)
} else {
return await orElse(document)
return await orElse(document ?? { name: '<aucune sélection>' })
}
}
static isOwnerPlayer(document) {
return document.testUserPermission && document.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)
return document?.isOwner
}
static isFirstOwnerPlayer(document) {
if (!document.testUserPermission) {
if (!document?.isOwner) {
return false
}
return game.users.find(u => document.testUserPermission(u, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)) == game.user
@@ -252,15 +255,15 @@ export class Misc {
* @returns true pour un seul utilisateur: le premier GM connecté par ordre d'id
*/
static isFirstConnectedGM() {
return game.user == Misc.firstConnectedGM();
return game.users.activeGM != undefined && game.user == game.users.activeGM
}
static hasConnectedGM() {
return Misc.firstConnectedGM();
return game.users.activeGM
}
static firstConnectedGMId() {
return Misc.firstConnectedGM()?.id;
return game.users.activeGM?.id;
}
/* -------------------------------------------- */

182
module/moral/apprecier.mjs Normal file
View File

@@ -0,0 +1,182 @@
import { ChatUtility } from "../chat-utility.js"
import { ITEM_TYPES } from "../constants.js"
import { SANS_COMPETENCE } from "../item/base-items.js"
import { Misc } from "../misc.js"
import { CARACS } from "../rdd-carac.js"
import { RdDUtility } from "../rdd-utility.js"
import { DIFF } from "../roll/roll-constants.mjs"
import RollDialog from "../roll/roll-dialog.mjs"
import { PART_COMP } from "../roll/roll-part-comp.mjs"
export const MORAL = {
MALHEUREUX: "malheureux",
NEUTRE: "neutre",
HEUREUX: "heureux",
TRESHEUREUX: "très heureux"
}
export const SITUATION_MORAL = {
[MORAL.MALHEUREUX]: "malheureuse",
[MORAL.NEUTRE]: "neutre",
[MORAL.HEUREUX]: "heureuse",
[MORAL.TRESHEUREUX]: "très heureuse",
}
export const APPRECIATION = {
CUISINE: {
bonmoment: "Cuisine", carac: CARACS.ODORATGOUT, competence: "Cuisine",
moral: MORAL.HEUREUX, jetComp: false, jetQualite: false, compMinimum: true
},
MUSIQUE: {
bonmoment: "Musique", carac: CARACS.OUIE, competence: "Musique",
moral: MORAL.HEUREUX, jetComp: false, jetQualite: false, compMinimum: true
},
CHANT: {
bonmoment: "Musique", carac: CARACS.OUIE, competence: "Chant",
moral: MORAL.HEUREUX, jetComp: false, jetQualite: false, compMinimum: true
},
DANSE: {
bonmoment: "Spectacle", carac: CARACS.EMPATHIE, competence: "Danse",
moral: MORAL.HEUREUX, jetComp: false, jetQualite: false, compMinimum: true
},
JEU: {
bonmoment: "Jeu", carac: CARACS.EMPATHIE, competence: "Jeu",
moral: MORAL.HEUREUX, jetComp: false, jetQualite: false, compMinimum: true
},
OEUVRE: {
bonmoment: "Spectacle", carac: CARACS.EMPATHIE, competence: "",
moral: MORAL.HEUREUX, jetComp: false, jetQualite: false, compMinimum: true
},
SERVICE: {
bonmoment: "Confort", carac: CARACS.EMPATHIE, competence: "",
moral: MORAL.HEUREUX, jetComp: false, jetQualite: false, compMinimum: false
},
}
export class Apprecier {
static isAppreciable(item) {
switch (item.type) {
case ITEM_TYPES.nourritureboisson:
case ITEM_TYPES.service:
return item.system.qualite > 0
case ITEM_TYPES.chant:
case ITEM_TYPES.musique:
case ITEM_TYPES.danse:
case ITEM_TYPES.oeuvre:
case ITEM_TYPES.jeu:
return true
}
return false
}
static qualite(qualite, roll = undefined, comp = undefined) {
if (roll && comp) {
return roll.rolled.isSuccess ? qualite : Math.min(qualite, comp.system.niveau)
}
return
}
static getAppreciation(qualite, appreciable, roll = undefined, comp = undefined) {
return {
qualite: (roll?.rolled.ptQualite ?? 0) + Apprecier.qualite(qualite, roll, comp),
appreciation: foundry.utils.duplicate(appreciable.system.appreciation),
messages: []
}
}
static onClickApprecier(roll) {
const appreciation = roll.result.appreciation
if (appreciation.moral == "") {
return
}
RdDUtility.doWithSelectedActor(
actor => new Apprecier(actor, appreciation, roll.result.qualite).apprecier(),
actor => actor.isPersonnage())
}
constructor(actor, appreciation, qualite) {
this.actor = actor
this.appreciation = foundry.utils.duplicate(appreciation)
this.appreciation.situation = SITUATION_MORAL[appreciation.moral]
this.qualite = qualite
this.raisons = []
}
apprecier(callbacks = []) {
if (this.qualite <= 0) {
this.raisons.push(`la qualité ${this.qualite} est insuffisante.`)
}
if (this.qualite <= this.actor.getMoralTotal()) {
this.raisons.push(`la qualité de ${this.qualite} est inférieure au moral de ${this.actor.getMoralTotal()}.`)
}
const competence = this.getCompetenceAppreciation()
if (this.appreciation.compMinimum && this.qualite <= competence.system.niveau && competence.system.niveau > 0 && competence.id) {
this.raisons.push(`la qualité ${this.qualite} est insuffisante pour le niveau ${competence.system.niveau} en ${competence.name}`)
}
const bonmoment = this.appreciation.bonmoment
if (!["", undefined].includes(bonmoment) && this.actor.system.compteurs.bonmoments.includes(bonmoment)) {
this.raisons.push(`du moral a déjà été gagné pour cause de ${bonmoment}`)
}
if (this.appreciation.carac != "") {
this.rollAppreciation(callbacks)
}
else {
this.rollMoral()
}
}
getCompetenceAppreciation() {
return [SANS_COMPETENCE.name, ""].includes(this.appreciation.competence) ? SANS_COMPETENCE : this.actor.getCompetence(this.appreciation.competence)
}
rollAppreciation(rollCallbacks = []) {
const competence = (this.appreciation.jetComp && this.appreciation.competence) ? this.appreciation.competence : ""
const rollData = {
ids: { actorId: this.actor.id },
type: { allowed: [PART_COMP], current: PART_COMP, appreciation: true },
selected: {
carac: { key: this.appreciation.carac, forced: true },
comp: { key: competence, forced: true },
diff: { type: DIFF.IMPOSEE },
apprecier: {
appreciation: this.appreciation,
qualite: this.qualite,
raisons: this.raisons
}
}
}
RollDialog.create(rollData, {
callbacks: [
async r => await this.onRollAppreciation(r),
...rollCallbacks
],
onRollDone: RollDialog.onRollDoneClose
})
}
async onRollAppreciation(roll) {
if (roll.rolled.isSuccess) {
await this.rollMoral()
}
else {
if (this.appreciation.moral == MORAL.TRESHEUREUX) {
await this.rollMoral(MORAL.HEUREUX)
}
}
}
async rollMoral(moral = undefined) {
if (this.raisons.length > 0) {
ChatMessage.create({
whisper: ChatUtility.getOwners(this.actor),
content: 'Pas de jet de moral:' + Misc.concat(this.raisons.map(r => `<br> - ${r}`))
})
return
}
moral = moral ?? this.appreciation.moral
// TODO: jet de moral
await this.actor.jetDeMoral(moral, this.appreciation.bonmoment)
}
}

View File

@@ -70,7 +70,7 @@ export class RdDBonus {
dmgParticuliere: RdDBonus._dmgParticuliere(rollData),
dmgSurprise: rollData.opponent?.surprise?.dmg ?? 0,
mortalite: RdDBonus.mortalite(attaque.dmg?.mortalite, arme?.system.mortalite),
dmgActor: RdDBonus.bonusDmg(actor, attaque.carac.key, dmgArme, attaque.forceRequise),
dmgActor: RdDBonus.bonusDmg(actor, attaque.carac?.key, dmgArme, attaque.forceRequise),
dmgForceInsuffisante: Math.min(0, actor.getForce() - (attaque.forceRequise ?? 0)),
dmgDiffLibre: ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(attaque.diff ?? 0) : 0
}

View File

@@ -61,7 +61,9 @@ export const CARACS = {
DEROBEE: 'derobee',
CHANCE_ACTUELLE: 'chance-actuelle',
REVE_ACTUEL: 'reve-actuel',
VIE: 'vie'
}
export const LIST_CARAC_PERSONNAGE = {
[CARACS.TAILLE]: { code: CARACS.TAILLE, label: 'Taille', isCarac: true, path: 'system.carac.taille.value' },
[CARACS.APPARENCE]: { code: CARACS.APPARENCE, label: 'Apparence', isCarac: true, path: 'system.carac.apparence.value' },
@@ -166,10 +168,18 @@ export class RdDCarac {
const total = Object.values(carac ?? {}).filter(c => !c.derivee)
.map(it => parseInt(it.value))
.reduce(Misc.sum(), 0);
const beauteSuperieur10 = Math.max((beaute ?? 10) - 10, 0);
const beauteSuperieur10 = Math.max((beaute ?? 10) - 10, 0)
return total + beauteSuperieur10;
}
static computeTotalXp(carac, beaute = undefined) {
const totalXp = Object.values(carac ?? {}).filter(c => !c.derivee)
.map(it => RdDCarac.getCaracXp(0, Misc.toInt(it.value)) + Misc.toInt(it.xp))
.reduce(Misc.sum(), 0);
const beauteXp = beaute > 10 ? RdDCarac.getCaracXp(10, beaute) : 0
return totalXp + beauteXp;
}
static levelUp(it) {
it.xpNext = RdDCarac.getCaracNextXp(it.value);
it.isLevelUp = (it.xp >= it.xpNext);
@@ -182,12 +192,16 @@ export class RdDCarac {
/* -------------------------------------------- */
static getCaracNextXp(value) {
const nextValue = Number(value) + 1;
value = Number(value);
const nextValue = value + 1;
// xp est le coût pour atteindre cette valeur, on regarde donc le coût de la valeur+1
return RdDCarac.getCaracXp(nextValue);
return RdDCarac.getCaracXp(value, nextValue)
}
static getCaracXp(targetValue) {
return RdDCarac.getCaracDerivee(targetValue)?.xp ?? 200;
static getCaracXp(from, to) {
return Array.from({ length: to - from },
(_, i) => from + i + 1)
.map(it => RdDCarac.getCaracDerivee(it)?.xp ?? 200)
.reduce(Misc.sum(), 0)
}
}

View File

@@ -19,6 +19,7 @@ import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll/roll-constants.mjs"
import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js";
import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs";
import { RollBasicParts } from "./roll/roll-basic-parts.mjs";
import { Distance } from "./combat/distance.mjs";
/* -------------------------------------------- */
const premierRoundInit = [
@@ -62,6 +63,10 @@ export class RdDCombatManager extends Combat {
it.token.id == tokenId
)
}
static getRangInitiativeCombatant(actorId, tokenId) {
const combatant = RdDCombatManager.getCombatant(actorId, tokenId)
return combatant?.system.init?.rang
}
/* -------------------------------------------- */
async nextRound() {
await this.finDeRound();
@@ -153,7 +158,7 @@ export class RdDCombatManager extends Combat {
alias: combatant.token?.name,
sound: CONFIG.sounds.dice,
},
flavor: `${combatant.token?.name} a une initiatyive de ${init.value} : ${messageOptions.info}<br>`
flavor: `${combatant.token?.name} a une initiative de ${init.value} : ${messageOptions.info}<br>`
},
messageOptions);
init.roll.toMessage(messageData, { rollMode, create: true });
@@ -369,8 +374,7 @@ export class RdDCombat {
}
static rddCombatForAttackV2(attackerRoll) {
const defenderRoll = RollBasicParts.prepareDefense(attackerRoll)
return RdDCombat.rddCombatForDefenseV2(defenderRoll)
return RdDCombat.rddCombatForDefenseV2(RollBasicParts.prepareDefense(attackerRoll))
}
static rddCombatForDefenseV2(defenderRoll) {
@@ -514,8 +518,8 @@ export class RdDCombat {
/* -------------------------------------------- */
attaqueChanceuse(attackerRoll) {
ui.notifications.info("L'attaque est rejouée grâce à la chance")
attackerRoll.essais.attaqueChance = true;
this.attaque(attackerRoll, attackerRoll.arme);
attackerRoll.essais.attaqueChance = true
this.attaque(attackerRoll, attackerRoll.arme)
}
/* -------------------------------------------- */
@@ -626,68 +630,27 @@ export class RdDCombat {
}
else {
const defenderToken = canvas.tokens.get(this.defenderTokenId)
const dist = this.distance(_token, defenderToken)
const isVisible = this.isVisible(_token, defenderToken)
const portee = this._ajustementPortee(dist, rollData.arme)
const taille = this._ajustementTaille(this.defender)
const activite = this._ajustementMouvement(this.defender)
const total = [portee, taille, activite].map(it => it.diff).filter(d => !Number.isNaN(d)).reduce(Misc.sum(), 0)
ChatMessage.create({
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-info-distance.hbs', {
const info = foundry.utils.mergeObject(
{
rollData: rollData,
attacker: _token,
isVisible: isVisible,
defender: defenderToken,
distance: dist,
portee: portee,
taille: taille,
activite: activite,
total: total
}),
},
Distance.ajustements(_token, defenderToken, { arme: rollData.arme, main: rollData.competence.system.categorie })
)
ChatMessage.create({
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-info-distance.hbs', info),
whisper: ChatUtility.getGMs()
})
}
}
}
isVisible(token, defenderToken) {
return canvas.effects.visibility.testVisibility(defenderToken.center, { object: token })
}
distance(token, defenderToken) {
return Number(canvas.grid.measureDistances([{ ray: new Ray(token.center, defenderToken.center) }], { gridSpaces: false })).toFixed(1);
}
_ajustementPortee(dist, arme) {
if (dist <= arme.system.portee_courte) return { msg: "courte", diff: 0 };
if (dist <= arme.system.portee_moyenne) return { msg: "moyenne", diff: -3 };
if (dist <= arme.system.portee_extreme) return { msg: "extrême", diff: -5 };
return { msg: "inatteignable", diff: -10 };
}
_ajustementTaille(actor) {
if (actor.isVehicule()) return { msg: "véhicule", diff: 0 }
const taille = actor.getCaracByName('TAILLE')?.value ?? 1;
if (taille <= 1) return { msg: "souris", diff: -8 };
if (taille <= 3) return { msg: "chat", diff: -4 };
if (taille <= 5) return { msg: "chien", diff: -2 };
if (taille <= 15) return { msg: "humanoïde", diff: 0 };
if (taille <= 20) return { msg: "ogre", diff: 2 };
return { msg: "gigantesque", diff: 4 };
}
_ajustementMouvement(defender) {
if (defender.getSurprise(true) != '') return { msg: "immobile (surprise)", diff: 0 };
if (game.combat?.combatants.find(it => it.actorId == defender.id)) return { msg: "en mouvement (combat)", diff: -4 };
return { msg: "à déterminer (0 immobile, -3 actif, -4 en mouvement, -5 en zig-zag)", diff: -3 };
}
async attaqueV2() {
async attaqueV2(options = undefined) {
if (!await this.attacker.accorder(this.defender, 'avant-attaque')) {
return
}
await this.doRollAttaque({
const rollData = {
ids: {
actorId: this.attackerId,
actorTokenId: this.attackerTokenId,
@@ -695,12 +658,22 @@ export class RdDCombat {
opponentTokenId: this.defenderTokenId,
},
type: { allowed: ['attaque'], current: 'attaque' },
selected: {},
passeArme: foundry.utils.randomID(16),
})
}
if (options) {
rollData.selected = {
attaque: {
comp: { id: options.comp.id },
arme: { id: options.arme.id },
main: options.main
}
}
}
await this.doRollAttaque(rollData)
}
async doRollAttaque(rollData, callbacks = []) {
// TODO V2 await this.proposerAjustementTirLancer(rollData)
return await RollDialog.create(rollData, {
onRollDone: RollDialog.onRollDoneClose,
callbacks: [
@@ -741,7 +714,7 @@ export class RdDCombat {
}
_socketSendMessageDefenseV2(paramChatDefense) {
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_defense_v2", data: {paramChatDefense} })
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_defense_v2", data: { paramChatDefense } })
}
static async onMsgDefenseV2(msg) {
@@ -755,7 +728,7 @@ export class RdDCombat {
}
async _chatMessageDefenseV2(paramDemandeDefense) {
const attackerRoll = paramDemandeDefense.attackerRoll;
const attackerRoll = paramDemandeDefense.attackerRoll
RollBasicParts.loadSurprises(attackerRoll)
attackerRoll.dmg = RdDBonus.dmgRollV2(attackerRoll, attackerRoll.current.attaque)
@@ -778,12 +751,14 @@ export class RdDCombat {
}
/* -------------------------------------------- */
async attaque(competence, arme) {
async attaque(competence, arme, main) {
if (!await this.attacker.accorder(this.defender, 'avant-attaque')) {
return
}
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
return this.attacker.rollCompetence(competence.name, { arme: arme })
return this.attaqueV2(
{ comp: competence, arme: arme, main: main }
)
}
if (arme.system.cac == EMPOIGNADE) {
RdDEmpoignade.onAttaqueEmpoignade(this.attacker, this.defender)
@@ -792,7 +767,7 @@ export class RdDCombat {
RdDEmpoignade.checkEmpoignadeEnCours(this.attacker)
let rollData = this._prepareAttaque(competence, arme)
console.log("RdDCombat.attaque >>>", rollData);
console.log("RdDCombat.attaque >>>", rollData)
if (arme) {
this.attacker.verifierForceMin(arme);
}
@@ -817,7 +792,7 @@ export class RdDCombat {
/* -------------------------------------------- */
_prepareAttaque(competence, arme) {
let rollData = {
mode: ROLL_TYPE_ATTAQUE,
mode: 'attaque',
alias: this.attacker?.getAlias(),
passeArme: foundry.utils.randomID(16),
mortalite: arme?.system.mortalite,
@@ -1085,8 +1060,7 @@ export class RdDCombat {
}
async defenseV2(attackerRoll, callbacks = []) {
// this._prepareParade(attackerRoll, arme, competence);
RollDialog.loadRollData(attackerRoll)
await this.doRollDefense({
ids: {
actorId: this.defender.id,
@@ -1421,6 +1395,7 @@ export class RdDCombat {
return
}
const alias = token?.name ?? actor.getAlias();
const blessuresGraves = actor.countBlessures(it => it.isGrave());
const formData = {
combatId: combat._id,
alias: alias,
@@ -1431,7 +1406,7 @@ export class RdDCombat {
actorId: actor.id,
actor: actor,
tokenId: token.id,
isGrave: actor.countBlessures(it => it.isGrave()) > 0,
blessuresGraves: blessuresGraves,
isCritique: actor.countBlessures(it => it.isCritique()) > 0
}
await ChatMessage.create({

View File

@@ -116,6 +116,7 @@ export class RdDCommands {
this.registerCommand({
path: ["/xp", "carac"], func: (content, msg, params) => this.getCoutXpCarac(msg, params),
descr: `Détermine le coût d'expérience pour augmenter une caractéristique. Exemples:
<br>/xp carac 12 15: coût pour passer de 12 15
<br>/xp carac 15: coût pour atteindre 15 (depuis 14)`
});
@@ -440,13 +441,18 @@ export class RdDCommands {
/* -------------------------------------------- */
getCoutXpCarac(msg, params) {
if (params && params.length == 1) {
let to = Number(params[0]);
return RdDCommands._chatAnswer(msg, `Coût pour passer une caractéristique de ${to - 1} à ${to}: ${RdDCarac.getCaracXp(to)}`);
}
else {
return false;
if (params) {
if (params.length == 1) {
const to = Number(params[0])
return RdDCommands._chatAnswer(msg, `Coût pour passer une caractéristique de ${to - 1} à ${to}: ${RdDCarac.getCaracXp(to - 1, to)}`);
}
if (params.length == 2) {
const from = Number(params[0]);
const to = Number(params[1]);
return RdDCommands._chatAnswer(msg, `Coût pour passer une caractéristique de ${from} à ${to}: ${RdDCarac.getCaracXp(from, to)}`);
}
}
return false
}
async creerSignesDraconiques() {

View File

@@ -89,20 +89,20 @@ export class RdDEmpoignade {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
RdDEmpoignade.entrainerAuSol(rollData)
ChatUtility.removeChatMessageId(chatMessage.id)
ChatUtility.remover(chatMessage)()
});
$(html).on("click", '.empoignade-projeter-sol', event => {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
RdDEmpoignade.projeterAuSol(rollData)
ChatUtility.removeChatMessageId(chatMessage.id)
ChatUtility.remover(chatMessage)()
});
$(html).on("change", '.empoignade-perte-endurance', event => {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
if (event.currentTarget.value && event.currentTarget.value != "none") {
RdDEmpoignade.perteEndurance(rollData, event.currentTarget.value)
//ChatUtility.removeChatMessageId(chatMessage.id)
ChatUtility.remover(chatMessage)()
}
});
}

View File

@@ -101,7 +101,7 @@ export class RdDHotbar {
}
/** Roll macro */
static rollMacro(itemName, itemType, categorieArme = 'competence') {
static rollMacro(itemName, itemType, maniement = 'competence') {
const speaker = ChatMessage.getSpeaker();
let actor;
if (speaker.token) actor = game.actors.tokens[speaker.token];
@@ -117,10 +117,10 @@ export class RdDHotbar {
// Trigger the item roll
switch (item.type) {
case ITEM_TYPES.arme:
return actor.rollArme(item, categorieArme);
return actor.rollArme(item, maniement);
case ITEM_TYPES.competence:
if (item.isCorpsACorps()) {
switch (categorieArme) {
switch (maniement) {
case PUGILAT:
return actor.rollArme(RdDItemArme.pugilat(actor));
case EMPOIGNADE:
@@ -130,7 +130,7 @@ export class RdDHotbar {
return actor.rollCompetence(item);
case ITEM_TYPES.competencecreature:
return item.system.iscombat
? actor.rollArme(item, categorieArme)
? actor.rollArme(item, maniement)
: actor.rollCompetence(item);
}

View File

@@ -1,5 +1,7 @@
import { SYSTEM_RDD, SYSTEM_SOCKET_ID, RDD_CONFIG, ITEM_TYPES } from "./constants.js"
const RDD_INFO_MESSAGE_URL = "https://gitea.scriptarium.org/Scriptarium/foundryvtt-reve-de-dragon/raw/branch/v13/info-message.html"
import { RdDUtility } from "./rdd-utility.js"
import { TMRUtility } from "./tmr-utility.js"
import { TMRRencontres } from "./tmr-rencontres.js"
@@ -90,6 +92,8 @@ import { Migrations } from './migrations.js'
import RollDialog from "./roll/roll-dialog.mjs"
import ChatRollResult from "./roll/chat-roll-result.mjs"
import ExportPdf from "./actor/export-pdf/export-pdf.mjs"
import { DialogFlushByDate } from "./chat/dialog-flush-by-date.mjs"
import { Remote } from "./remote.mjs"
/**
* RdD system
@@ -181,6 +185,7 @@ export class SystemReveDeDragon {
game.socket.on(SYSTEM_SOCKET_ID, async (sockmsg) => {
console.log(">>>>> MSG RECV", sockmsg)
try {
Remote.onSocketMessage(sockmsg)
RdDUtility.onSocketMessage(sockmsg)
RdDCombat.onSocketMessage(sockmsg)
ChatUtility.onSocketMessage(sockmsg)
@@ -247,11 +252,11 @@ export class SystemReveDeDragon {
ITEM_TYPES.jeu,
ITEM_TYPES.race,
ITEM_TYPES.recettecuisine,
ITEM_TYPES.oeuvre,
ITEM_TYPES.oeuvre,
ITEM_TYPES.meditation,
ITEM_TYPES.queue,
ITEM_TYPES.ombre,
ITEM_TYPES.souffle,
ITEM_TYPES.ombre,
ITEM_TYPES.souffle,
ITEM_TYPES.tete,
ITEM_TYPES.casetmr,
ITEM_TYPES.sort,
@@ -300,6 +305,7 @@ export class SystemReveDeDragon {
ExportPdf.init()
RollDialog.init()
ChatRollResult.init()
DialogFlushByDate.init()
}
initSettings() {
@@ -352,6 +358,15 @@ export class SystemReveDeDragon {
},
default: "aucun"
})
/* -------------------------------------------- */
game.settings.register(SYSTEM_RDD, "info-msg-timeout", {
name: "Gestion du timeout d'affichage du message d'information",
scope: "world",
config: false,
type: Number,
default: 0
})
}
async onReady() {
@@ -410,10 +425,33 @@ export class SystemReveDeDragon {
<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>
` })
// Get last message display time
const lastDisplay = game.settings.get(SYSTEM_RDD, "info-msg-timeout") || 0
const now = Date.now()
const oneDayMs = 24 * 60 * 60 * 1000
if (now - lastDisplay < oneDayMs) {
return // Already displayed in the last 24 hours
}
// Update last display time
game.settings.set(SYSTEM_RDD, "info-msg-timeout", now)
// Try to fetch the welcome message from the github repo RDD_INFO_MESSAGE_URL
fetch(RDD_INFO_MESSAGE_URL)
.then(response => response.text())
.then(html => {
console.log("Fetched welcome message:", html);
ChatMessage.create({
user: game.user.id,
whisper: [game.user.id],
content: html
});
})
.catch(error => {
console.error("Error fetching welcome message:", error);
});
}
}
roll(rollData, actors, options){
roll(rollData, actors, options) {
RollDialog.create(rollData, actors, options)
}
}

View File

@@ -0,0 +1,261 @@
import { ITEM_TYPES, RDD_CONFIG } from "./constants.js";
import { RollBasicParts } from "./roll/roll-basic-parts.mjs";
import { ChatUtility } from "./chat-utility.js";
import RollDialog from "./roll/roll-dialog.mjs";
import { Targets } from "./targets.js";
import { RdDUtility } from "./rdd-utility.js";
import { ROLL_TYPE_POSSESSION } from "./roll/roll-constants.mjs";
import { TokenActor } from "./technical/actor-token.mjs";
export const ACTIONS_POSSESSION = {
ATTAQUE: 'attaque',
POSSEDER: 'posseder',
CONJURER: 'conjurer',
DEFENSE: 'defense',
DEFENSE_POSSESSION: 'defense-possession',
DEFENSE_CONJURATION: 'defense-conjuration'
}
export class RdDPossessionV2 {
static init() {
}
static $isInverse(entite, victime) {
return !entite.actor.isEntiteNonIncarnee() && victime.actor.isEntiteNonIncarnee()
}
/* -------------------------------------------- */
static findPossession(entite, victime) {
if (RdDPossessionV2.$isInverse(entite, victime)) {
return RdDPossessionV2.findPossession(victime, entite)
}
return victime.actor.itemTypes[ITEM_TYPES.possession].find(it => it.system.entiteid == entite.id)
}
static async createPossessionIfMissing(entite, victime) {
if (RdDPossessionV2.$isInverse(entite, victime)) {
return await RdDPossessionV2.createPossessionIfMissing(victime, entite)
}
const existing = RdDPossessionV2.findPossession(entite, victime)
if (!existing) {
await victime.actor.createEmbeddedDocuments('Item', [{
name: `Possession de ${entite.name}`,
type: ITEM_TYPES.possession,
img: RDD_CONFIG.icons.possession,
system: {
entiteid: entite.actor.id,
entitetokenid: entite.token.id,
victimeid: victime.actor.id,
victimetokenid: victime.token.id,
compteur: 0
}
}])
}
}
static getTypePossession(active, opponent) {
const itemPossession = RdDPossessionV2.findPossession(active, opponent)
const isEntite = active.actor.isEntiteNonIncarnee() && !opponent.actor.isEntiteNonIncarnee()
const compteur = itemPossession?.system.compteur ?? 0
return {
isEntite: isEntite,
isPersonnage: active.actor.isPersonnage(),
isCompteurPossession: Math.sign(compteur) >= 0,
compteur: Math.abs(compteur)
}
}
static getTypePossessionAction(active, opponent, action) {
const possession = RdDPossessionV2.getTypePossession(active, opponent)
possession.isAttaque = RdDPossessionV2.isAttaque(action)
possession.action = RdDPossessionV2.$getAction(possession.isAttaque, possession.isEntite)
return possession
}
static $getAction(isAttaque, isEntite) {
if (isAttaque) {
return isEntite ? ACTIONS_POSSESSION.POSSEDER : ACTIONS_POSSESSION.CONJURER
}
return isEntite ? ACTIONS_POSSESSION.DEFENSE_CONJURATION : ACTIONS_POSSESSION.DEFENSE_POSSESSION
}
static actionTitle(action) {
switch (action) {
case ACTIONS_POSSESSION.POSSEDER: return "tente de posséder"
case ACTIONS_POSSESSION.CONJURER: return "tente de conjurer"
case ACTIONS_POSSESSION.DEFENSE_POSSESSION: return "résiste à la possession de"
case ACTIONS_POSSESSION.DEFENSE_CONJURATION: return "résiste à la conjuration de"
case ACTIONS_POSSESSION.DEFENSE: return "résiste à "
}
return "lutte contre"
}
static isDefense(action) {
return [ACTIONS_POSSESSION.DEFENSE, ACTIONS_POSSESSION.DEFENSE_POSSESSION, ACTIONS_POSSESSION.DEFENSE_CONJURATION].includes(action)
}
static isAttaque(action) {
return [ACTIONS_POSSESSION.ATTAQUE, ACTIONS_POSSESSION.POSSEDER, ACTIONS_POSSESSION.CONJURER].includes(action)
}
static async rollAttaquePossession(actor) {
const selectedToken = RdDUtility.getSelectedToken(actor)
Targets.selectOneTargetToken(async target => {
RollDialog.create(
{
ids: {
actorId: actor.id,
actorTokenId: selectedToken.id,
opponentId: target.actor.id,
opponentTokenId: target.id
},
passeArme: foundry.utils.randomID(16),
type: { allowed: [ROLL_TYPE_POSSESSION], current: ROLL_TYPE_POSSESSION, possession: { action: ACTIONS_POSSESSION.ATTAQUE } },
},
{
onRollDone: RollDialog.onRollDoneClose,
callbacks: [
async (roll) => await RdDPossessionV2.createPossessionIfMissing(roll.active, roll.opponent),
async (roll) => RdDPossessionV2.$setParticuliereFinesse(roll),
async (roll) => await RdDPossessionV2.chatMessageDefensePossession(roll)
]
})
})
}
static async rollConjurerPossession(actor, possession) {
if (possession.system.possede){
ui.notifications.warn(`${actor.name} est totalement possédé, impossible de conjurer l'entité`)
return
}
RollDialog.create(
{
ids: {
actorId: possession.system.victimeid,
actorTokenId: possession.system.victimetokenid,
opponentId: possession.system.entiteid,
opponentTokenId: possession.system.entitetokenid
},
passeArme: foundry.utils.randomID(16),
type: { allowed: [ROLL_TYPE_POSSESSION], current: ROLL_TYPE_POSSESSION, possession: { action: ACTIONS_POSSESSION.ATTAQUE } },
},
{
onRollDone: RollDialog.onRollDoneClose,
callbacks: [
async (roll) => await RdDPossessionV2.createPossessionIfMissing(roll.active, roll.opponent),
async (roll) => RdDPossessionV2.$setParticuliereFinesse(roll),
async (roll) => await RdDPossessionV2.chatMessageDefensePossession(roll)
]
})
}
static $setParticuliereFinesse(roll) {
if (roll.rolled.isPart) {
roll.particuliere = RDD_CONFIG.particuliere.finesse.key
}
}
static async rollDefensePossession(savedRoll, chatMessage) {
RollBasicParts.restore(savedRoll)
const attackerRoll = savedRoll.attackerRoll
RollDialog.create(
{
ids: savedRoll.ids,
passeArme: attackerRoll.passeArme,
type: { allowed: [ROLL_TYPE_POSSESSION], current: ROLL_TYPE_POSSESSION, possession: { action: ACTIONS_POSSESSION.DEFENSE } },
selected: { diff: { value: attackerRoll.selected?.diff?.value ?? 0 } },
attackerRoll: attackerRoll
},
{
onRollDone: RollDialog.onRollDoneClose, callbacks: [
async roll => await RdDPossessionV2.onRollDefense(roll),
ChatUtility.remover(chatMessage)
]
});
}
static async onRollDefense(defense) {
if (defense.rolled.isEchec) {
await RdDPossessionV2.addPointPossession(defense.opponent, defense.active)
}
RdDPossessionV2.resetPossession(defense)
}
static async onMarquerPointPossession(roll) {
roll.type = {}
await RdDPossessionV2.addPointPossession(roll.opponent, roll.active)
RdDPossessionV2.resetPossession(roll)
await ChatMessage.create({
// message privé: du défenseur à lui même (et aux GMs)
speaker: ChatMessage.getSpeaker({ actor: roll.active.actor, token: roll.active.token }),
alias: roll.opponent.name,
whisper: ChatUtility.getOwners(roll.active.actor),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/possession/chat-message-marquer.hbs`, roll)
})
}
static resetPossession(roll) {
roll.type.possession = foundry.utils.mergeObject(
roll.type.possession ?? {},
RdDPossessionV2.getTypePossession(roll.opponent, roll.active))
}
static async addPointPossession(entite, victime, points = 1) {
if (RdDPossessionV2.$isInverse(entite, victime)) {
return await RdDPossessionV2.addPointPossession(victime, entite, - points)
}
const existing = RdDPossessionV2.findPossession(entite, victime)
if (existing) {
const compteur = (existing.system.compteur ?? 0) + points
await victime.actor.updateEmbeddedDocuments('Item', [{ _id: existing.id, 'system.compteur': compteur }])
}
}
static async chatMessageDefensePossession(attackerRoll) {
const defense = RollBasicParts.prepareDefense(attackerRoll)
defense.type = {
possession: RdDPossessionV2.getTypePossessionAction(defense.active, defense.opponent, ACTIONS_POSSESSION.DEFENSE)
}
const chatDemandeDefense = await ChatMessage.create({
// message privé: du défenseur à lui même (et aux GMs)
speaker: ChatMessage.getSpeaker({ actor: defense.active.actor, token: defense.active.token }),
alias: attackerRoll.active.name,
whisper: ChatUtility.getOwners(defense.active.actor),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/possession/chat-demande-defense.hbs', defense)
});
ChatUtility.setMessageData(chatDemandeDefense, 'demande-defense', true)
// // flag pour garder les jets d'attaque/defense
ChatUtility.setMessageData(chatDemandeDefense, 'rollData', {
ids: defense.ids,
attackerRoll: RollDialog.saveParts(attackerRoll),
passeArme: defense.passeArme
})
}
static async onPossession(actor, possession) {
if (Math.abs(possession.system.compteur) >= 2) {
await ChatMessage.create({
alias: actor.getAlias(),
whisper: ChatUtility.getOwners(actor),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/possession/chat-fin-possession.hbs', {
possession,
active: TokenActor.fromActor(actor),
opponent: TokenActor.fromActor(game.actors.get(possession.system.entiteid))
})
})
if (possession.system.compteur <= -2) {
await actor.deleteEmbeddedDocuments('Item', [possession.id])
}
if (possession.system.compteur >= 2) {
await actor.updateEmbeddedDocuments('Item', [{ _id: possession.id, 'system.possede': true }])
}
}
}
}

View File

@@ -2,6 +2,7 @@ import { RdDRoll } from "./rdd-roll.js";
import { Targets } from "./targets.js";
import { ITEM_TYPES } from "./constants.js";
import { RdDRollResult } from "./rdd-roll-result.js";
import { CARACS } from "./rdd-carac.js";
/* -------------------------------------------- */
/* On part du principe qu'une entité démarre tjs
@@ -18,9 +19,9 @@ export class RdDPossession {
/* -------------------------------------------- */
static searchPossessionFromEntite(attacker, defender) {
let poss = attacker.items.find(poss => poss.type == ITEM_TYPES.possession && poss.system.victime.actorid == defender.id);
let poss = attacker.itemTypes[ITEM_TYPES.possession].find(poss => poss.system.victime.actorid == defender.id);
if (!poss) {
poss = defender.items.find(poss => poss.type == ITEM_TYPES.possession && poss.system.victime.actorid == defender.id);
poss = defender.itemTypes[ITEM_TYPES.possession].find(poss => poss.system.victime.actorid == defender.id);
}
return poss && foundry.utils.duplicate(poss) || undefined;
}
@@ -94,17 +95,16 @@ export class RdDPossession {
}
static selectCompetenceDraconicOuPossession(rollData, rollingActor) {
rollData.competence = rollingActor.getDraconicOuPossession();
rollData.competence = rollingActor.getDraconicOuPossession().find(it => true);
if (rollingActor.isCreatureOuEntite()) {
const carac = rollingActor.system.carac
rollData.carac = carac
rollData.competence.system.defaut_carac = 'reve'
rollData.selectedCarac = carac.reve
rollData.carac = rollingActor.system.carac
rollData.competence.system.defaut_carac = CARACS.REVE
rollData.selectedCarac = rollingActor.system.carac.reve
}
else {
rollData.forceCarac = { 'reve-actuel': { label: "Rêve Actuel", value: rollingActor.getReveActuel() } }
rollData.selectedCarac = rollData.forceCarac['reve-actuel']
rollData.competence.system.defaut_carac = 'reve-actuel'
rollData.forceCarac = rollingActor.getCaracReveActuel()
rollData.selectedCarac = rollData.forceCarac[CARACS.REVE_ACTUEL]
rollData.competence.system.defaut_carac = CARACS.REVE_ACTUEL
}
}
@@ -132,7 +132,7 @@ export class RdDPossession {
}
const possession = (rollData.isECNIDefender ? rollData.attacker : rollData.defender).getPossession(rollData.possession.system.possessionid)
RdDPossession.storePossessionAttaque(possession, rollData)
await RdDRollResult.displayRollData(rollData, rollData.defender, 'chat-resultat-possession.hbs');
await RdDRollResult.displayRollData(rollData, rollData.defender, 'chat-resultat-possession-v1.hbs');
}
/* -------------------------------------------- */
@@ -172,7 +172,7 @@ export class RdDPossession {
rollData.possession = possession
RdDPossession.$updateEtatPossession(rollData.possession)
await RdDRollResult.displayRollData(rollData, rollData.attacker, 'chat-resultat-possession.hbs')
await RdDRollResult.displayRollData(rollData, rollData.attacker, 'chat-resultat-possession-v1.hbs')
if (rollData.possession.isPosseder || rollData.possession.isConjurer) {
// conjuration
await victime.deleteEmbeddedDocuments("Item", [rollData.possession._id])
@@ -226,15 +226,18 @@ export class RdDPossession {
/* -------------------------------------------- */
static async createPossession(attacker, defender) {
return await Item.create({
name: "Possession en cours de " + attacker.name, type: 'possession',
img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
name: `Possession de ${entite.name}`,
type: ITEM_TYPES.possession,
img: RDD_CONFIG.icons.possession,
system: {
description: "", typepossession: attacker.name,
typepossession: attacker.name,
possede: false,
possessionid: foundry.utils.randomID(16),
entiteid: attacker.id,
victimeid: defender.id,
compteur: 0,
entite: { actorid: attacker.id },
victime: { actorid: defender.id },
compteur: 0
victime: { actorid: defender.id }
}
},
{

View File

@@ -16,7 +16,7 @@ export class RdDEncaisser extends Dialog {
/* -------------------------------------------- */
constructor(html, actor) {
if (actor.isEntiteNonIncarnee([ENTITE_NONINCARNE])) {
if (actor.isEntiteNonIncarnee()) {
throw `${actor.name} est une entité non incarnée et ne peut pas subnir de dommages`
}

View File

@@ -4,7 +4,7 @@ import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemSort } from "./item-sort.js";
import { Misc } from "./misc.js";
import { RdDBonus } from "./rdd-bonus.js";
import { RdDCarac } from "./rdd-carac.js";
import { CARACS, RdDCarac } from "./rdd-carac.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { Grammar } from "./grammar.js";
@@ -65,7 +65,7 @@ export class RdDRoll extends Dialog {
}
// Mini patch :Ajout du rêve actuel
if (actor.type == ACTOR_TYPES.personnage) {
defaultRollData.carac["reve-actuel"] = actor.system.reve.reve
defaultRollData.carac[CARACS.REVE_ACTUEL] = actor.system.reve.reve
}
foundry.utils.mergeObject(rollData, defaultRollData, { recursive: true, overwrite: false });

View File

@@ -93,7 +93,7 @@ export class RdDSheetUtility {
static async renderItemBranch(actor, item) {
while (item) {
await item.sheet?.render()
item = actor.getContenant(item)
item = actor.findConteneur(item)
}
}
}

View File

@@ -13,10 +13,10 @@ import { Draconique } from "./tmr/draconique.js";
import { HtmlUtility } from "./html-utility.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { RdDDice } from "./rdd-dice.js";
import { STATUSES } from "./settings/status-effects.js";
import { RdDRencontre } from "./item/rencontre.js";
import { ITEM_TYPES } from "./constants.js";
import { Misc } from "./misc.js";
import { CARACS } from "./rdd-carac.js";
const TMR_DISPLAY_SIZE = {
code: 'tmr-display-size',
@@ -126,7 +126,7 @@ export class RdDTMRDialog extends Dialog {
HtmlUtility.showControlWhen(this.html.find(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(this._getCoordActor()));
this.html.find('form.tmr-dialog *').click(event => {
if (this.subdialog?.rendered){
if (this.subdialog?.rendered) {
this.subdialog?.bringToFront()
}
})
@@ -187,7 +187,9 @@ export class RdDTMRDialog extends Dialog {
async restoreTMRAfterAction() {
this.subdialog = undefined
await this.maximize()
this.bringToFront()
if (this.rendered) {
this.bringToFront()
}
}
forceTMRContinueAction() {
@@ -348,10 +350,10 @@ export class RdDTMRDialog extends Dialog {
return false
}
this.descenteTMR = true
await await this.actor.quitterTMR(message, this.viewOnly, this.cumulFatigue)
this.pixiTMR.close();
await await this.actor?.quitterTMR(message, this.viewOnly, this.cumulFatigue)
this.pixiTMR?.close()
this.pixiTMR = undefined
await super.close();
await super.close()
return true
}
@@ -684,12 +686,12 @@ export class RdDTMRDialog extends Dialog {
tmr: tmr,
canClose: false,
diffLibre: -7,
forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: this.actor.getReveActuel() } },
forceCarac: this.actor.getCaracReveActuel(),
maitrise: { verbe: 'maîtriser', action: 'Maîtriser le fleuve' }
}
rollData.double = EffetsDraconiques.isDoubleResistanceFleuve(this.actor) ? true : undefined,
rollData.competence.system.defaut_carac = 'reve-actuel';
await this._rollMaitriseCaseHumide(rollData);
rollData.double = EffetsDraconiques.isDoubleResistanceFleuve(this.actor) ? true : undefined
rollData.competence.system.defaut_carac = CARACS.REVE_ACTUEL
await this._rollMaitriseCaseHumide(rollData)
}
}
@@ -809,30 +811,30 @@ export class RdDTMRDialog extends Dialog {
tmr: tmr,
canClose: options.canClose ?? false,
diffLibre: options.difficulte ?? -7,
forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: this.actor.getReveActuel() } },
forceCarac: this.actor.getCaracReveActuel(),
maitrise: { verbe: 'conquérir', action: options.action }
};
rollData.competence.system.defaut_carac = 'reve-actuel';
}
rollData.competence.system.defaut_carac = CARACS.REVE_ACTUEL
await this._maitriserTMR(rollData, r => this._onResultatConquerir(r, options));
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 });
rollData.souffle = await this.actor.ajouterSouffle({ chat: false })
}
rollData.poesie = await Poetique.getExtrait();
rollData.poesie = await Poetique.getExtrait()
ChatMessage.create({
whisper: ChatUtility.getOwners(this.actor),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.hbs`, rollData)
});
})
if (rollData.rolled.isEchec) {
options.onConqueteEchec(rollData, options.effetDraconique);
options.onConqueteEchec(rollData, options.effetDraconique)
}
else {
await options.onConqueteReussie(rollData, options.effetDraconique);
this.updateTokens();
await options.onConqueteReussie(rollData, options.effetDraconique)
this.updateTokens()
}
}
@@ -966,7 +968,7 @@ export class RdDTMRDialog extends Dialog {
const targetOddq = this.pixiTMR.computeEventOddq(event)
const targetCoord = TMRUtility.oddqToCoordTMR(targetOddq)
if (targetCoord == COORD_TMR_INCONNU){
if (targetCoord == COORD_TMR_INCONNU) {
ui.notifications.error("Vous ne pouvez pas vous déplacer ici");
return
}

View File

@@ -34,7 +34,7 @@ export class RdDTokenHud {
const actor = RdDCombatManager.getActorCombatant(combatant, { warning: false })
if (actor) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
await RdDTokenHud.addExtensionHudCombat(html, combatant, actor, token)
await RdDTokenHud.addExtensionHudCombatV2(html, combatant, actor, token)
}
else {
const actions = RdDCombatManager.listActionsActorCombatant(actor)
@@ -47,17 +47,28 @@ export class RdDTokenHud {
}
}
static async addExtensionHudCombat(html, combatant, actor, token) {
const actionsActor = actor.listActionsCombat();
static async addExtensionHudCombatV2(html, combatant, actor, token) {
const isPossession = actor.listActionsPossessions().length > 0;
const actionsCombat = isPossession ? [] : actor.listAttaques()
const ajustements = combatant?.initiative ?
[
{ label: 'Initiative +1', action: 'delta', value: 1 },
{ label: 'Initiative -1', action: 'delta', value: -1 }
] : []
const autres = [{ label: "Autre action", action: 'autre' }]
const actions = Misc.indexed(actionsActor.concat(ajustements).concat(autres))
const actions = Misc.indexed([
...actionsCombat,
...ajustements,
...autres
])
const hudData = { combatant, token, actions };
const hudData = {
combatant,
token,
isPossession,
isEntiteNonIncarnee: actor.isEntiteNonIncarnee(),
actions,
};
const hud = $(await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/hud-actor-combat.hbs', hudData))
$(html).find('div.col.left').append(hud)
@@ -84,6 +95,7 @@ export class RdDTokenHud {
}
})
list.find('.rdd-attaque-v2').click(event => combatant.actor.rollAttaque(token))
list.find('.rdd-possession-v2').click(event => combatant.actor.rollPossession())
}
static async addExtensionHudInit(html, combatant, actions) {

View File

@@ -18,7 +18,7 @@ import { RdDEmpoignade } from "./rdd-empoignade.js";
import { ExperienceLog } from "./actor/experience-log.js";
import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { APP_ASTROLOGIE_REFRESH } from "./sommeil/app-astrologie.js";
import { ITEM_TYPES, RDD_CONFIG, SYSTEM_RDD } from "./constants.js";
import { ACTOR_TYPES, ITEM_TYPES, RDD_CONFIG, SYSTEM_RDD } from "./constants.js";
import { RdDBaseActor } from "./actor/base-actor.js";
import { RdDCarac } from "./rdd-carac.js";
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
@@ -26,6 +26,8 @@ import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
import { RdDItemCompetence } from "./item-competence.js";
import { Monnaie } from "./item-monnaie.js";
import { ItemAction } from "./item/item-actions.js";
import { Targets } from "./targets.js";
import { DialogSelect } from "./dialog-select.js";
/* -------------------------------------------- */
// This table starts at 0 -> niveau -10
@@ -180,9 +182,14 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.hbs',
'systems/foundryvtt-reve-de-dragon/templates/item/partial-environnement.hbs',
'systems/foundryvtt-reve-de-dragon/templates/item/partial-tab-environnement.hbs',
'systems/foundryvtt-reve-de-dragon/templates/header-item.hbs',
'systems/foundryvtt-reve-de-dragon/templates/item/queue-sheet.hbs',
'systems/foundryvtt-reve-de-dragon/templates/item/partial-header.hbs',
'systems/foundryvtt-reve-de-dragon/templates/item/partial-hautrevant.hbs',
'systems/foundryvtt-reve-de-dragon/templates/item/partial-frequence.hbs',
'systems/foundryvtt-reve-de-dragon/templates/item/partial-description.hbs',
'systems/foundryvtt-reve-de-dragon/templates/item/partial-appreciable.hbs',
'systems/foundryvtt-reve-de-dragon/templates/item/enum-appreciation-bonmoment.hbs',
'systems/foundryvtt-reve-de-dragon/templates/item/enum-appreciation-carac.hbs',
'systems/foundryvtt-reve-de-dragon/templates/item/enum-appreciation-moral.hbs',
// partial enums
'systems/foundryvtt-reve-de-dragon/templates/enum-aspect-tarot.hbs',
'systems/foundryvtt-reve-de-dragon/templates/enum-base-competence.hbs',
@@ -232,9 +239,6 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-moral.hbs',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-surenc.hbs',
'systems/foundryvtt-reve-de-dragon/templates/partial-select-carac.hbs',
'systems/foundryvtt-reve-de-dragon/templates/partial-item-hautrevant.hbs',
'systems/foundryvtt-reve-de-dragon/templates/partial-item-frequence.hbs',
'systems/foundryvtt-reve-de-dragon/templates/partial-item-description.hbs',
'systems/foundryvtt-reve-de-dragon/templates/roll/explain.hbs',
'systems/foundryvtt-reve-de-dragon/templates/resolution-table.hbs',
// Dialogs
@@ -344,7 +348,8 @@ export class RdDUtility {
// Items
Handlebars.registerHelper('rarete-getChamp', (rarete, field) => RdDRaretes.getChamp(rarete, field));
Handlebars.registerHelper('item-action-applies', (action, item, options) => ItemAction.applies(action, item, options))
Handlebars.registerHelper('item-action-icon', (action, item) => ItemAction.icon(action, item))
Handlebars.registerHelper('item-action-label', (action, item) => new Handlebars.SafeString(ItemAction.label(action, item)))
Handlebars.registerHelper('item-action-img', (action, item) => new Handlebars.SafeString(ItemAction.img(action, item)))
Handlebars.registerHelper('item-name', (item) => item.nameDisplay)
// TMRs
@@ -776,8 +781,9 @@ export class RdDUtility {
let sommeAPayer = Number(event.currentTarget.attributes['data-somme-a-payer']?.value ?? 0);
let actor = RdDUtility.getSelectedActor("Pour effectuer le paiement:");
if (actor) {
actor.payerSols(sommeAPayer);
ChatUtility.removeChatMessageId(RdDUtility.findChatMessageId(event.currentTarget));
actor.payerSols(sommeAPayer)
const chatMessage = RdDUtility.findChatMessageId(event.currentTarget)
ChatUtility.remover(chatMessage)()
}
});
$(html).on("click", '.rdd-world-content-link', async event => {
@@ -846,6 +852,26 @@ export class RdDUtility {
return undefined;
}
static doWithSelectedActor(onSelected = () => { }, filter = actor => true) {
const selected = RdDUtility.getSelectedActor()
if (selected) {
onSelected(selected)
}
else {
const actors = game.actors
.filter(it => it.getUserLevel(game.user) == CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)
.filter(it => ![ACTOR_TYPES.commerce, ACTOR_TYPES.vehicule].includes(it.type))
.filter(filter)
const selectData = {
title: "Choisir un acteur",
label: "Choisir un acteur",
list: actors.map(it => Targets.extractActorData(it))
};
DialogSelect.select(selectData, it => onSelected(game.actors.get(it.id)))
}
}
/* -------------------------------------------- */
static createMonnaie(name, cout, img = "", enc = 0.01) {
let piece = {

53
module/remote.mjs Normal file
View File

@@ -0,0 +1,53 @@
import { RdDBaseActor } from "./actor/base-actor.js";
import { SYSTEM_SOCKET_ID } from "./constants.js";
import { Misc } from "./misc.js";
export class Remote {
static onSocketMessage(sockmsg) {
switch (sockmsg.msg) {
case "msg_remote_call":
return Remote.onRemoteCall(sockmsg.userId, sockmsg.data);
}
}
static remoteCall({ userId = undefined, documentName, documentId, tokenId = undefined, method, args }) {
const callData = { documentName, documentId, tokenId, method, args }
const sendToUserId = Misc.connectedUserOrGM(userId)
if (sendToUserId == undefined) {
ui.notifications.error(`Impossible d'envoyer un message à ${userId}`)
}
else if (sendToUserId == game.user.id) {
Remote.onRemoteCall(game.user.id, callData)
return false
}
else {
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_remote_call", userId: sendToUserId, data: callData })
return true
}
}
static onRemoteCall(userId, callData) {
if (userId == game.user.id) {
// Seul le joueur choisi effectue l'appel: le joueur courant si propriétaire de l'actor, ou le MJ sinon
const doc = Remote.getDoc(callData)
if (doc) {
const args = callData.args;
const method = callData.method;
console.info(`Remote.onRemoteCall: ${callData.documentName} ${callData.documentId}, appel de ${method}(`, ...args, ')')
doc[method](...args)
}
}
}
static getDoc(callData) {
switch (callData.documentName) {
case 'Actor': return RdDBaseActor.getRealActor(callData.documentId, callData.tokenId)
case 'Item': return game.items.get(callData.documentId)
case 'RollTable': return game.tables.get(callData.documentId)
case 'ChatMessage': return game.messages.get(callData.documentId)
}
return undefined
}
}

View File

@@ -13,6 +13,10 @@ import { PART_ATTAQUE } from "./roll-part-attaque.mjs"
import { RdDRollTables } from "../rdd-rolltables.js"
import { RdDEmpoignade } from "../rdd-empoignade.js"
import { Misc } from "../misc.js"
import { RollBasicParts } from "./roll-basic-parts.mjs"
import { RdDPossessionV2 } from "../rdd-possession-v2.mjs"
import { Apprecier } from "../moral/apprecier.mjs"
import { Remote } from "../remote.mjs"
export default class ChatRollResult {
static init() {
@@ -23,14 +27,16 @@ export default class ChatRollResult {
static onReady() {
foundry.applications.handlebars.loadTemplates({
'partial-infojet': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-infojet.hbs',
'partial-appel-chance': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-appel-chance.hbs',
'partial-apprecier': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-apprecier.hbs',
'partial-appreciation': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-appreciation.hbs',
'partial-attaque-particuliere': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-attaque-particuliere.hbs',
'partial-choix-maladresse': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-choix-maladresse.hbs',
'partial-maladresse': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-maladresse.hbs',
'partial-encaissement': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-encaissement.hbs',
'partial-recul-choc': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-recul-choc.hbs',
'partial-infojet': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-infojet.hbs',
'partial-info-appel-moral': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-info-appel-moral.hbs',
'partial-maladresse': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-maladresse.hbs',
'partial-recul-choc': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-recul-choc.hbs',
})
}
@@ -44,28 +50,28 @@ export default class ChatRollResult {
roll.active.actor,
roll.current?.rollmode?.key
)
const save = RollDialog.saveParts(roll, impacts)
await this.saveChatMessageRoll(chatMessage, save)
await this.saveChatMessageRoll(chatMessage, roll, impacts)
return chatMessage
}
prepareDisplay(roll) {
roll.done = roll.done ?? {}
roll.show = roll.show ?? {}
roll.show.chance = this.isAppelChancePossible(roll)
roll.show.encaissement = this.isShowEncaissement(roll)
roll.show.recul = this.getRecul(roll)
roll.show.maladresse = this.getMaladresse(roll)
roll.show.chance = this.$isAppelChancePossible(roll)
roll.show.encaissement = this.$isShowEncaissement(roll)
roll.show.recul = this.$getRecul(roll)
roll.show.maladresse = this.$getMaladresse(roll)
}
isAppelChancePossible(roll) {
$isAppelChancePossible(roll) {
return roll.active.actor.isPersonnage() &&
roll.rolled.isEchec &&
RdDCarac.isActionPhysique(roll.current.carac?.key)
RdDCarac.isActionPhysique(roll.current.carac?.key) &&
!roll.type.appreciation
}
isShowEncaissement(roll) {
$isShowEncaissement(roll) {
switch (roll.type.current) {
case ROLL_TYPE_DEFENSE:
return roll.rolled.isEchec
@@ -73,7 +79,7 @@ export default class ChatRollResult {
return false
}
getMaladresse(roll) {
$getMaladresse(roll) {
switch (roll.type.current) {
case ROLL_TYPE_DEFENSE:
if (roll.rolled.isETotal) {
@@ -91,7 +97,7 @@ export default class ChatRollResult {
return undefined
}
getRecul(roll, defender = roll.active.actor, attacker = roll.opponent?.actor) {
$getRecul(roll, defender = roll.active.actor, attacker = roll.opponent?.actor) {
switch (roll.type.current) {
case ROLL_TYPE_DEFENSE:
{
@@ -134,10 +140,13 @@ export default class ChatRollResult {
$(html).on("click", '.appel-chance', event => this.onClickAppelChance(event))
$(html).on("click", '.appel-destinee', event => this.onClickAppelDestinee(event))
$(html).on("click", '.button-defense', event => this.onClickDefense(event))
$(html).on("click", '.button-defense-possession', event => this.onClickDefensePossession(event))
$(html).on("click", '.marquer-point-possession', event => this.onClickMarquerPointPossession(event))
$(html).on("click", '.encaissement', event => this.onClickEncaissement(event))
$(html).on("click", '.resister-recul', event => this.onClickRecul(event))
$(html).on("click", '.choix-particuliere', event => this.onClickChoixParticuliere(event))
$(html).on("click", '.faire-gouter', event => this.onClickFaireGouter(event))
$(html).on("click", '.apprecier', event => this.onClickApprecier(event))
$(html).on("click", '.monter-tmr-normale', event => this.onClickMonteeTMR(event, 'normal'))
$(html).on("click", '.monter-tmr-rapide', event => this.onClickMonteeTMR(event, 'rapide'))
$(html).on("click", '.tirer-maladresse', event => this.onClickTirerMaladresse(event))
@@ -153,60 +162,72 @@ export default class ChatRollResult {
return undefined
}
async saveChatMessageRoll(chatMessage, savedRoll) {
await ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll)
}
loadChatMessageRoll(chatMessage) {
return ChatUtility.getMessageData(chatMessage, 'rollData')
getActiveActor(roll) {
return roll.active?.actor ?? (roll.ids?.actorId ? game.actors.get(roll.ids.actorId) : undefined)
}
async updateChatMessage(chatMessage, savedRoll) {
RollDialog.loadRollData(savedRoll)
savedRoll.dmg = savedRoll.current.attaque?.dmg
await this.saveChatMessageRoll(chatMessage, savedRoll)
const copy = foundry.utils.duplicate(savedRoll)
RollDialog.loadRollData(copy)
savedRoll.dmg = copy.current.attaque?.dmg
this.prepareDisplay(copy)
chatMessage.update({ content: await this.buildRollHtml(copy) })
chatMessage.render(true)
this.prepareDisplay(savedRoll)
const content = await this.buildRollHtml(savedRoll)
Remote.remoteCall({
userId: chatMessage.author.id,
documentName: chatMessage.documentName,
documentId: chatMessage.id,
method: 'update',
args: [{ content: content }, { render: true }]
})
}
async saveChatMessageRoll(chatMessage, roll, impacts = undefined) {
const save = RollDialog.saveParts(roll, impacts)
await ChatUtility.setMessageData(chatMessage, 'rollData', save)
}
loadChatMessageRoll(chatMessage) {
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
RollBasicParts.restore(savedRoll)
return savedRoll
}
onClickAppelChance(event) {
event.preventDefault()
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
const actor = game.actors.get(savedRoll.ids.actorId)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, it => it.rollAppelChance(
() => this.onAppelChanceSuccess(savedRoll, chatMessage),
() => this.onAppelChanceEchec(savedRoll, chatMessage))
)
}
async onAppelChanceSuccess(savedRoll, chatMessage) {
const reRoll = foundry.utils.duplicate(savedRoll)
console.log('onAppelChanceSuccess savedRoll', savedRoll)
reRoll.type.retry = true
await this.updateChatMessage(chatMessage, reRoll)
const callbacks = [r => ChatUtility.removeChatMessageId(chatMessage.id)]
async onAppelChanceSuccess(roll, chatMessage) {
roll.type.retry = true
await this.updateChatMessage(chatMessage, roll)
// TODO: annuler les effets
switch (reRoll.type.current) {
const callbacks = [ChatUtility.remover(chatMessage)]
// TODO: annuler les effets...
switch (roll.type.current) {
case ROLL_TYPE_DEFENSE:
this.getCombat(reRoll)?.doRollDefense(reRoll, callbacks)
this.getCombat(roll)?.doRollDefense(roll, callbacks)
break
case ROLL_TYPE_ATTAQUE:
// TODO
this.getCombat(reRoll)?.doRollAttaque(reRoll, callbacks)
this.getCombat(roll)?.doRollAttaque(roll, callbacks)
break
default: {
await RollDialog.create(reRoll, { onRollDone: RollDialog.onRollDoneClose, callbacks })
await RollDialog.create(roll, { onRollDone: RollDialog.onRollDoneClose, callbacks })
}
}
}
async onAppelChanceEchec(savedRoll, chatMessage) {
savedRoll.type.retry = true
await this.updateChatMessage(chatMessage, savedRoll)
async onAppelChanceEchec(roll, chatMessage) {
roll.type.retry = true
await this.updateChatMessage(chatMessage, roll)
}
onClickAppelDestinee(event) {
@@ -214,33 +235,53 @@ export default class ChatRollResult {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
const actor = game.actors.get(savedRoll.ids.actorId)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, it => it.appelDestinee(async () => {
const reRoll = foundry.utils.duplicate(savedRoll)
reRoll.type.retry = true
RdDResolutionTable.significativeRequise(reRoll.rolled)
await this.updateChatMessage(chatMessage, reRoll)
savedRoll.type.retry = true
RdDResolutionTable.significativeRequise(savedRoll.rolled)
await this.updateChatMessage(chatMessage, savedRoll)
}))
}
async onClickDefense(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
const attackerRoll = savedRoll.attackerRoll
this.getCombat(attackerRoll)?.defenseV2(attackerRoll,
[roll => { ChatUtility.removeChatMessageId(chatMessage.id) }]
)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, it => {
const attackerRoll = savedRoll.attackerRoll
RollDialog.loadRollData(attackerRoll)
this.getCombat(attackerRoll)?.defenseV2(attackerRoll,
[ChatUtility.remover(chatMessage)]
)
})
}
async onClickDefensePossession(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, it => RdDPossessionV2.rollDefensePossession(savedRoll, chatMessage))
}
async onClickMarquerPointPossession(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, async it => {
await RdDPossessionV2.onMarquerPointPossession(savedRoll)
ChatUtility.remover(chatMessage)()
})
}
async onClickEncaissement(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const isMessageDemande = ChatUtility.getMessageData(chatMessage, 'demande-defense')
const savedRoll = this.loadChatMessageRoll(chatMessage)
const attaque = savedRoll.attackerRoll
const defenderToken = savedRoll.ids.actorTokenId ? canvas.tokens.get(savedRoll.ids.actorTokenId) : undefined
const defender = defenderToken?.actor ?? game.actors.get(savedRoll.ids.actorId)
Misc.doIfOwner(defender, async defender => {
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, async defender => {
const defenderToken = savedRoll.active.token
const attaque = savedRoll.attackerRoll
const attackerToken = savedRoll.ids.opponentTokenId ? canvas.tokens.get(savedRoll.ids.opponentTokenId) : undefined
const attacker = attackerToken?.actor ?? game.actors.get(savedRoll.ids.opponentId)
switch (attaque.dmg.mortalite) {
@@ -255,7 +296,7 @@ export default class ChatRollResult {
break
}
if (isMessageDemande) {
ChatUtility.removeChatMessageId(chatMessage.id)
ChatUtility.remover(chatMessage)()
} else {
savedRoll.done.encaissement = true
await this.updateChatMessage(chatMessage, savedRoll)
@@ -266,9 +307,8 @@ export default class ChatRollResult {
async onClickRecul(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
// TODO: gestion sur token non liés?
const defender = game.actors.get(savedRoll.ids.actorId)
Misc.doIfOwner(defender, async defender => {
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, async defender => {
const attacker = game.actors.get(savedRoll.ids.opponentId)
savedRoll.done.recul = await defender.encaisserRecul(attacker.getForce(), savedRoll.attackerRoll.dmg.dmgArme)
await this.updateChatMessage(chatMessage, savedRoll)
@@ -279,37 +319,54 @@ export default class ChatRollResult {
const choix = event.currentTarget.attributes['data-particuliere'].value
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
savedRoll.particuliere = choix
savedRoll.particulieres = [RDD_CONFIG.particuliere[choix]]
await this.updateChatMessage(chatMessage, savedRoll)
await this.getCombat(savedRoll)?.onAttaqueV2(savedRoll)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, async it => {
savedRoll.particuliere = choix
savedRoll.particulieres = [RDD_CONFIG.particuliere[choix]]
await this.updateChatMessage(chatMessage, savedRoll)
await this.getCombat(savedRoll)?.onAttaqueV2(savedRoll)
})
}
async onClickFaireGouter(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
if (!savedRoll.type.retry) {
savedRoll.type.retry = true
await this.updateChatMessage(chatMessage, savedRoll)
}
await new RollTypeCuisine().onFaireGouter(savedRoll)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, async it => {
if (!savedRoll.type.retry) {
savedRoll.type.retry = true
await this.updateChatMessage(chatMessage, savedRoll)
}
await new RollTypeCuisine().onFaireGouter(savedRoll)
})
}
async onClickApprecier(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
Apprecier.onClickApprecier(savedRoll)
}
async onClickMonteeTMR(event, mode) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
if (await new RollTypeMeditation().onMonteeTMR(savedRoll, mode)) {
savedRoll.done.meditation = true
await this.updateChatMessage(chatMessage, savedRoll)
}
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, async it => {
if (await new RollTypeMeditation().onMonteeTMR(savedRoll, mode)) {
savedRoll.done.meditation = true
await this.updateChatMessage(chatMessage, savedRoll)
}
})
}
async onClickTirerMaladresse(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const typeMaladresse = event.currentTarget.attributes['data-maladresse'].value
const savedRoll = this.loadChatMessageRoll(chatMessage)
savedRoll.maladresse = await RdDRollTables.getMaladresse({ arme: typeMaladresse == 'avec-arme', toChat: false })
savedRoll.type.retry = true
await this.updateChatMessage(chatMessage, savedRoll)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, async it => {
savedRoll.maladresse = await RdDRollTables.getMaladresse({ arme: typeMaladresse == 'avec-arme', toChat: false })
savedRoll.type.retry = true
await this.updateChatMessage(chatMessage, savedRoll)
})
}
}

View File

@@ -11,7 +11,7 @@ export class RollBasicParts {
rollData.ids.sceneId = rollData.ids.sceneId ?? canvas.scene.id
rollData.active = RollBasicParts.getTokenActor(rollData)
rollData.opponent = RollBasicParts.getTokenActorOpponent(rollData)
if (rollData.type.opposed == undefined) {
if (rollData.type && rollData.type.opposed == undefined) {
rollData.type.opposed = rollData.opponent != null
}
}
@@ -46,10 +46,10 @@ export class RollBasicParts {
type: rollData.type,
ids: {
sceneId: rollData.ids.sceneId,
actorId: rollData.active.id,
actorTokenId: rollData.active.tokenId,
opponentId: isOpposed ? rollData.opponent.id : undefined,
opponentTokenId: isOpposed ? rollData.opponent.tokenId : undefined,
actorId: rollData.ids.actorId,
actorTokenId: rollData.ids.actorTokenId,
opponentId: isOpposed ? rollData.ids.opponentId : undefined,
opponentTokenId: isOpposed ? rollData.ids.opponentTokenId : undefined,
}
}
}

View File

@@ -1,5 +1,6 @@
export const ROLL_TYPE_ATTAQUE = 'attaque'
export const ROLL_TYPE_POSSESSION = 'possession'
export const ROLL_TYPE_COMP = 'comp'
export const ROLL_TYPE_CUISINE = 'cuisine'
export const ROLL_TYPE_DEFENSE = 'defense'
@@ -12,8 +13,7 @@ export const ROLL_TYPE_TACHE = 'tache'
export const ATTAQUE_ROLL_TYPES = [ROLL_TYPE_ATTAQUE]
export const COMBAT_ROLL_TYPES = [ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE]
export const DEMIREVE_ROLL_TYPES = [ROLL_TYPE_SORT]
export const DEFAULT_ROLL_TYPES = [ROLL_TYPE_COMP, ROLL_TYPE_ATTAQUE, ROLL_TYPE_TACHE, ROLL_TYPE_MEDITATION, ROLL_TYPE_CUISINE, ROLL_TYPE_OEUVRE, ROLL_TYPE_JEU]
export const DEFAULT_ROLL_TYPES = [ROLL_TYPE_COMP, ROLL_TYPE_TACHE, ROLL_TYPE_MEDITATION, ROLL_TYPE_CUISINE, ROLL_TYPE_OEUVRE, ROLL_TYPE_JEU]
export const DIFF = {
LIBRE: 'libre',
@@ -27,8 +27,8 @@ export const DIFF = {
export const DIFFS = {
[DIFF.LIBRE]: { key: DIFF.LIBRE, label: "Difficulté libre", libre: true, visible: true, max: 0 },
[DIFF.ATTAQUE]: { key: DIFF.ATTAQUE, label: "Difficulté d'attaque", libre: true, visible: true, max: 0 },
[DIFF.IMPOSEE]: { key: DIFF.IMPOSEE, label: "Diffficulté imposée", libre: false, visible: true, max: 0 },
[DIFF.DEFENSE]: { key: DIFF.DEFENSE, label: "Diffficulté défense", libre: false, visible: true, max: 0 },
[DIFF.IMPOSEE]: { key: DIFF.IMPOSEE, label: "Difficulté imposée", libre: false, visible: true, max: 20 },
[DIFF.DEFENSE]: { key: DIFF.DEFENSE, label: "Difficulté défense", libre: false, visible: true, max: 0 },
[DIFF.DEFAUT]: { key: DIFF.DEFAUT, label: "Difficulté", libre: true, visible: true, max: 5 },
[DIFF.AUCUN]: { key: DIFF.AUCUN, label: "", libre: false, visible: false, max: 0 },
}

View File

@@ -50,7 +50,7 @@ export class RollDialogAdapter {
rolled.factorHtml = Misc.getFractionOneN(rollData.current.sign.diviseur)
if (ReglesOptionnelles.isUsing("afficher-colonnes-reussite")) {
rolled.niveauNecessaire = RdDResolutionTable.findNiveauNecessaire(rolled.caracValue, rolled.roll)
rolled.ajustementNecessaire = rolled.niveauNecessaire - diff
rolled.ajustementNecessaire = rolled.niveauNecessaire - rolled.finalLevel
}
return rolled
}
@@ -92,10 +92,6 @@ export class RollDialogAdapter {
if (rollData.current[PART_APPELMORAL]?.checked) {
rollData.use.moral = true
}
if (ReglesOptionnelles.isUsing("afficher-colonnes-reussite")) {
rolled.niveauNecessaire = RdDResolutionTable.findNiveauNecessaire(rollData.selectedCarac.value, rolled.roll)
rolled.ajustementNecessaire = rolled.niveauNecessaire - diff
}
rollData.ajustements = rollData.ajustements.map(a => { return { label: a.label, value: a.value } })
}

View File

@@ -42,12 +42,14 @@ import ChatRollResult from "./chat-roll-result.mjs";
import { renderTemplate } from "../constants.js";
import { RollTypeCuisine } from "./roll-type-cuisine.mjs";
import { RollPartCuisine } from "./roll-part-cuisine.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2_TEST } from "../settings/options-avancees.js";
import { ActorImpacts } from "../technical/actor-impacts.mjs";
import { RollPartEmpoignade } from "./roll-part-empoignade.mjs";
import { RollPartEmpoignadeTaille } from "./roll-part-empoignade-taille.mjs";
import { RollPartEcailles } from "./roll-part-ecailles.mjs";
import { RollPartResistance } from "./roll-part-resistance.mjs";
import { RollTypePossession } from "./roll-type-possession.mjs";
import { RollPartPossession } from "./roll-part-possession.mjs";
import { RollPartApprecier } from "./roll-part-apprecier.mjs";
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api
@@ -56,6 +58,7 @@ export const ALL_ROLL_TYPES = [
new RollTypeComp(),
new RollTypeTache(),
new RollTypeAttaque(),
new RollTypePossession(),
new RollTypeDefense(),
new RollTypeSort(),
new RollTypeMeditation(),
@@ -75,7 +78,9 @@ const ROLL_PARTS = [
new RollPartComp(),
new RollPartDiff(),
new RollPartApprecier(),
new RollPartAttaque(),
new RollPartPossession(),
new RollPartDefense(),
new RollPartMeditation(),
new RollPartSort(),
@@ -193,9 +198,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
}
static onRollDoneClose(dialog, roll) {
if (roll.type.retry || !OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST)) {
dialog.close()
}
dialog.close()
}
static init() { }
@@ -215,7 +218,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
foundry.applications.handlebars.loadTemplates(ALL_ROLL_TYPES.map(m => m.chatResultTemplate))
foundry.applications.handlebars.loadTemplates(ROLL_PARTS.map(p => p.template))
ROLL_PARTS.forEach(p => p.onReady())
ROLL_PARTS.forEach(p => p.onReady(ROLL_PARTS))
Handlebars.registerHelper('roll-centered-array', (base, show) => {
show = Math.abs(show)
@@ -283,6 +286,13 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
// rien pour l'instant
}
static getAllowedParts(rollData) {
return rollData.type?.allowed
? ROLL_PARTS.filter(p => RollDialog.$isIntersecting(rollData.type.allowed, p.rollTypes))
: ROLL_PARTS
}
/** pre-configure les paramètres des différentes parties de la fenêtre (par exemple, prépare les listes de caractéristiques/compétences */
static $prepareRollData(rollData) {
rollData.current = rollData.current ?? {}
@@ -296,16 +306,18 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
? [potential]
: (rollData.type.allowed ?? ALL_ROLL_TYPES.filter(m => m.isAllowed(rollData) && m.visible(rollData)).map(m => m.code) ?? [ROLL_TYPE_COMP])
const rollType = allowed.find(c => c == rollData.type.current) ?? allowed[0]
const allowedRollParts = RollDialog.getAllowedParts(rollData)
rollData.type.allowed = allowed
rollData.type.current = rollType
ALL_ROLL_TYPES.find(m => m.code == rollType).setRollDataType(rollData)
rollData.refs = foundry.utils.mergeObject(rollData.refs ?? {}, Object.fromEntries(ROLL_PARTS.map(p => [p.code, {}])));
rollData.refs = foundry.utils.mergeObject(rollData.refs ?? {}, Object.fromEntries(allowedRollParts.map(p => [p.code, {}])));
rollData.options = rollData.options ?? { rollMode: game.settings.get("core", "rollMode") }
ROLL_PARTS.forEach(p => p.initialize(rollData))
ROLL_PARTS.filter(p => p.isValid(rollData))
allowedRollParts.forEach(p => RollDialog.$initializeRollPart(rollData, p.code))
allowedRollParts
.filter(p => p.isValid(rollData))
.forEach(p => {
p.restore(rollData)
p.loadRefs(rollData)
@@ -314,15 +326,43 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
return rollData
}
static saveParts(rollData, impacts) {
static $initializeRollPart(rollData, code) {
rollData.refs[code] = rollData.refs[code] ?? {}
rollData.current[code] = rollData.current[code] ?? {}
rollData.selected[code] = rollData.selected[code] ?? {}
}
static $isIntersecting(allowed, included) { return included ? included.find(it => allowed.includes(it)) : true }
static saveParts(rollData, impacts = undefined) {
if (rollData == undefined) {
return undefined
}
function saveBasics(from, to) {
if (from) {
to.ids = from.ids
to.passeArme = from.passeArme
to.rolled = from.rolled
to.particuliere = from.particuliere
to.result = from.result
to.done = from.done ?? {}
to.dmg = from.dmg
if (from.attackerRoll) {
to.attackerRoll = {}
saveBasics(from.attackerRoll, to.attackerRoll)
}
if (from.current) {
// stockage de current
RollDialog.getAllowedParts(from)
.filter(p => p.isActive(from))
.forEach(p => p.storeClean(from, target))
}
}
}
const target = RollBasicParts.initFrom(rollData)
ROLL_PARTS.filter(p => p.isActive(rollData))
.forEach(p => p.storeClean(rollData, target))
target.attackerRoll = rollData.attackerRoll
target.rolled = rollData.rolled
target.result = rollData.result
target.done = rollData.done ?? {}
target.dmg = rollData.dmg
saveBasics(rollData, target)
if (impacts) {
target.reverse = {
active: impacts.active?.reverseImpacts(),
@@ -330,6 +370,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
}
}
return target
}
constructor(rollData, rollOptions) {
@@ -347,12 +388,14 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
onClose: rollOptions.onClose ?? RollDialog.onCloseDoNothing
}
this.chatRollResult = new ChatRollResult()
this.rollParts = RollDialog.getAllowedParts(rollData)
this.selectType()
this.registerHooks(rollData);
this.registerHooks(rollData)
}
registerHooks(rollData) {
ROLL_PARTS.filter(p => p.isValid(rollData))
this.rollParts.filter(p => p.isValid(rollData))
.forEach(p => p.getHooks(this).forEach(h => {
const hook = h.hook;
const id = Hooks.on(hook, h.fn)
@@ -366,18 +409,18 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
selectType() {
const selectedType = this.getSelectedType();
this.rollData.type.label = selectedType.title(this.rollData)
const selectedType = this.getSelectedType()
selectedType.prepare(this.rollData)
selectedType.setRollDataType(this.rollData)
selectedType.onSelect(this.rollData)
this.rollData.type.label = selectedType.title(this.rollData)
ROLL_PARTS.find(it => it.code == PART_CARAC).filterCaracs(this.rollData)
ROLL_PARTS.find(it => it.code == PART_COMP).filterComps(this.rollData)
this.rollParts.find(it => it.code == PART_CARAC).filterCaracs(this.rollData)
this.rollParts.find(it => it.code == PART_COMP).filterComps(this.rollData)
}
static getActiveParts(rollData) {
return ROLL_PARTS.filter(p => p.isActive(rollData))
getActiveParts() {
return this.rollParts.filter(p => p.isActive(this.rollData))
}
rollTitle(rollData) {
@@ -412,12 +455,13 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
))
Promise.all(
RollDialog.getActiveParts(this.rollData).map(async p => await p._onRender(this, context, options))
this.getActiveParts().map(async p => await p._onRender(this, context, options))
)
}
static getAjustements(rollData) {
return RollDialog.getActiveParts(rollData)
return RollDialog.getAllowedParts(rollData)
.filter(p => p.isActive(rollData))
.map(p => p.getAjustements(rollData))
.reduce((a, b) => a.concat(b))
.sort((a, b) => a.value == undefined ? 1 : b.value == undefined ? -1 : 0)
@@ -434,8 +478,8 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
.map(m => m.toTypeData(rollData))
RollBasicParts.loadSurprises(rollData, this.getSelectedType().code)
rollData.type.label = this.getSelectedType()?.title(rollData)
//TOCHECK: set type.label ?
const visibleRollParts = RollDialog.getActiveParts(rollData)
const visibleRollParts = this.getActiveParts()
visibleRollParts.forEach(p => p.applyExternalImpacts(visibleRollParts, rollData))
this.setSpecialComp(visibleRollParts);
@@ -444,7 +488,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
RollDialog.calculAjustement(rollData)
const templates = RollDialog.getActiveParts(rollData).map(p => p.toTemplateData())
const templates = visibleRollParts.map(p => p.toTemplateData())
const context = await super._prepareContext()
return foundry.utils.mergeObject(
{
@@ -458,8 +502,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
const specialComp = visibleRollParts.map(p => p.getSpecialComp(this.rollData))
.reduce((a, b) => a.concat(b))
if (specialComp.length > 0) {
const rollPartComp = RollDialog.getActiveParts(this.rollData)
.find(it => it.code == PART_COMP);
const rollPartComp = this.getActiveParts().find(it => it.code == PART_COMP)
rollPartComp?.setSpecialComp(this.rollData, specialComp)
}
}
@@ -499,12 +542,15 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
roll.result = selectedRollType.getResult(roll, impacts)
console.info('RollDialog.roll:', roll)
const callbacks = [
...this.rollOptions.callbacks,
...selectedRollType.callbacks(this.rollOptions),
...this.rollOptions.callbacks,
]
await Promise.all(callbacks.map(async callback => await callback(roll)))
for (let callback of callbacks) {
await callback(roll)
}
await impacts.applyImpacts()
selectedRollType.onApplyImpacts(roll, impacts)
@@ -514,6 +560,9 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
static loadRollData(roll) {
RollDialog.$prepareRollData(roll)
if (roll.attackerRoll) {
RollDialog.$prepareRollData(roll.attackerRoll)
}
RollDialog.calculAjustement(roll)
roll.v2 = true
return roll

View File

@@ -0,0 +1,32 @@
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs";
export const PART_APPRECIER = "apprecier"
export class RollPartApprecier extends RollPart {
get code() { return PART_APPRECIER }
get section() { return ROLLDIALOG_SECTION.CHOIX }
restore(rollData) {
this.setCurrent(rollData, this.getSaved(rollData))
}
store(rollData, targetData) {
this.setSaved(targetData, this.getCurrent(rollData))
}
visible(rollData) {
return rollData.type.appreciation
}
getAjustements(rollData) {
const current = this.getCurrent(rollData)
if (current.appreciation.jetQualite){
return [{
label: 'Qualité',
value: Math.abs(current.qualite)
}]
}
return []
}
}

View File

@@ -1,7 +1,11 @@
import { Distance } from "../combat/distance.mjs"
import { RDD_CONFIG } from "../constants.js"
import { MAP_PHASE, RdDInitiative } from "../initiative.mjs"
import { ATTAQUE_TYPE_MELEE } from "../item/arme.js"
import { Misc } from "../misc.js"
import { RdDBonus } from "../rdd-bonus.js"
import { CARACS } from "../rdd-carac.js"
import { RdDCombatManager } from "../rdd-combat.js"
import { RdDEmpoignade } from "../rdd-empoignade.js"
import { DIFF, ROLL_TYPE_ATTAQUE, ROLL_TYPE_COMP } from "./roll-constants.mjs"
import RollDialog from "./roll-dialog.mjs"
@@ -10,28 +14,31 @@ import { PART_COMP } from "./roll-part-comp.mjs"
import { PART_DIFF } from "./roll-part-diff.mjs"
import { RollPartSelect } from "./roll-part-select.mjs"
import { PART_SIGN } from "./roll-part-sign.mjs"
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
export const PART_ATTAQUE = 'attaque'
const TACTIQUES = RdDBonus.tactiques.filter(it => it.isTactique)
const FILTER_ATTAQUE_EMPOIGNADE = attaque => attaque.arme.isEmpoignade()
const FILTER_ATTAQUE_NON_EMPOIGNADE = attaque => !attaque.arme.isEmpoignade()
const FILTER_ATTAQUE_EMPOIGNE = attaque => attaque.arme.isUtilisableEmpoigne() && ATTAQUE_TYPE_MELEE.includes(attaque.main)
const FILTER_ATTAQUE_EMPOIGNADE = attaque => attaque.arme?.isEmpoignade()
const FILTER_ATTAQUE_RANG = rang => attaque => !attaque.arme?.isEmpoignade() && (attaque.rang == rang || rang == undefined)
const FILTER_ATTAQUE_EMPOIGNE = attaque => attaque.arme?.isUtilisableEmpoigne() && ATTAQUE_TYPE_MELEE.includes(attaque.main)
export class RollPartAttaque extends RollPartSelect {
get code() { return PART_ATTAQUE }
get section() { return ROLLDIALOG_SECTION.CHOIX }
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_ATTAQUE) }
get rollTypes() { return [ROLL_TYPE_ATTAQUE] }
visible(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_ATTAQUE) }
loadRefs(rollData) {
const refs = this.getRefs(rollData)
const attaques = rollData.active.actor.listAttaques()
refs.all = attaques.map(it => RollPartAttaque.$extractAttaque(it, rollData.active.actor))
this.filterAttaquesEmpoignade(rollData)
.sort(Misc.descending(it => it.comp?.system.niveau ?? -8))
refs.all = attaques.map(it => RollPartAttaque.$extractAttaque(it, rollData))
this.filterAttaquesInitiative(rollData)
refs.tactiques = TACTIQUES
if (refs.attaques.length > 0) {
const attaque = this.findAttaque(refs.attaques, this.getSaved(rollData))
@@ -43,49 +50,63 @@ export class RollPartAttaque extends RollPartSelect {
return it.arme.isEmpoignade()
}
store(rollData, targetData) {
super.store(rollData, targetData)
this.getSaved(targetData).dmg = this.getCurrent(rollData).dmg
}
restore(rollData) {
const saved = this.getSaved(rollData)
super.restore(rollData)
if (saved.dmg != undefined) {
this.getCurrent(rollData).dmg = this.getSaved(rollData).dmg
const saved = this.getSaved(rollData) ?? {}
if (saved.key) {
this.setCurrent(rollData, {
key: saved.key,
tactique: saved.tactique,
dmg: saved.dmg
})
}
}
store(rollData, targetData) {
const current = this.getCurrent(rollData)
this.setSaved(targetData, {
key: current.key,
tactique: current.tactique,
dmg: current.dmg
})
}
findAttaque(attaques, saved) {
return attaques.find(at => at.arme.id == saved?.arme?.id &&
at.comp.id == saved?.comp?.id
return attaques.find(at => at.arme.id == (saved?.arme?.id ?? at.arme.id)
&& at.comp.id == (saved?.comp?.id ?? at.comp.id)
&& at.main == (saved?.main ?? at.main)
)
}
choices(refs) { return refs.attaques }
static $extractAttaque(attaque, actor) {
static $extractAttaque(attaque, rollData) {
attaque.key = `${attaque.action}::${attaque.label}`
attaque.tactique = TACTIQUES[0]
attaque.initialDiff = attaque.comp?.system.default_diffLibre ?? 0
attaque.distance = Distance.ajustements(rollData.active?.token, rollData.opponent?.token, attaque)
attaque.rang = RdDInitiative.phaseArme(attaque.comp?.system.categorie, attaque.arme)?.rang
return attaque
}
prepareContext(rollData) {
this.filterAttaquesEmpoignade(rollData)
this.filterAttaquesInitiative(rollData)
const current = this.getCurrent(rollData)
current.dmg = RdDBonus.dmgRollV2(rollData, current)
}
filterAttaquesEmpoignade(rollData) {
filterAttaquesInitiative(rollData) {
const refs = this.getRefs(rollData)
const isEmpoignade = RdDEmpoignade.isCombatantEmpoignade(rollData.ids.actorId, rollData.ids.actorTokenId)
const rang = RdDCombatManager.getRangInitiativeCombatant(rollData.ids.actorId, rollData.ids.actorTokenId)
const isEmpoignade = MAP_PHASE.empoignade.rang == rang
//const isEmpoignade = RdDEmpoignade.isCombatantEmpoignade(rollData.ids.actorId, rollData.ids.actorTokenId)
refs.isEmpoignadeEnCours = RdDEmpoignade.isEmpoignadeEnCours(rollData.active.actor)
const filterAttaques = isEmpoignade ?
FILTER_ATTAQUE_EMPOIGNADE
: refs.isEmpoignadeEnCours
? FILTER_ATTAQUE_EMPOIGNE
: FILTER_ATTAQUE_NON_EMPOIGNADE
: FILTER_ATTAQUE_RANG(rang)
refs.attaques = refs.all.filter(filterAttaques)
}
@@ -98,24 +119,30 @@ export class RollPartAttaque extends RollPartSelect {
$selectAttaque(rollData, key) {
const tactique = this.getCurrent(rollData).tactique
this.selectByKey(rollData, key)
if (tactique) {
this.getCurrent(rollData).tactique = tactique
}
}
async _onRender(rollDialog, context, options) {
const inputDiff = rollDialog.element.querySelector(`roll-section[name="diff"] input[name="diff"]`)
const selectAttaque = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-attaque"]`)
const selectTactique = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-tactique"]`)
const checkMortalite = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="check-mortalite"]`)
const utiliserDagueEmpoignade = rollDialog.element.querySelector(`roll-section[name="${this.code}"] a.utiliser-dague-empoignade`)
const current = this.getCurrent(rollDialog.rollData)
const rollData = rollDialog.rollData
const current = this.getCurrent(rollData)
selectAttaque.addEventListener("change", e => {
selectAttaque?.addEventListener("change", e => {
const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex
this.$selectAttaque(rollDialog.rollData, selectOptions[index]?.value)
this.$selectAttaque(rollData, selectOptions[index]?.value)
rollDialog.render()
})
selectTactique.addEventListener("change", e => {
selectTactique?.addEventListener("change", e => {
const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex
current.tactique = RdDBonus.find(selectOptions[index]?.value)
@@ -128,9 +155,11 @@ export class RollPartAttaque extends RollPartSelect {
})
utiliserDagueEmpoignade?.addEventListener("click", e => {
e.preventDefault()
const rollData = rollDialog.rollData
this.utiliserDagueEmpoignade(rollData)
})
inputDiff?.addEventListener("input", e => {
this.getRefs(rollData).all.forEach(attaque => attaque.initialDiff = undefined)
})
}
utiliserDagueEmpoignade(rollData) {
@@ -150,11 +179,14 @@ export class RollPartAttaque extends RollPartSelect {
if (this.visible(rollData)) {
const current = this.getCurrent(rollData)
switch (part.code) {
case PART_CARAC: return part.filterCaracs(rollData, [current.carac.key])
case PART_COMP: return part.filterComps(rollData, [current.comp.name])
case PART_CARAC: return part.filterCaracs(rollData, [current.carac?.key])
case PART_COMP: return part.filterComps(rollData, [current.comp?.name])
case PART_DIFF: {
if (current.initialDiff) {
part.setDiff(rollData, { type: DIFF.ATTAQUE, value: current.initialDiff })
if (Distance.typeAttaqueDistance(current)) {
part.setDiff(rollData, { type: DIFF.DEFAUT })
}
else {
part.setDiff(rollData, { type: DIFF.ATTAQUE, diff: current.initialDiff })
current.initialDiff = undefined
}
break

View File

@@ -1,5 +1,7 @@
import { Grammar } from "../grammar.js"
import { Misc } from "../misc.js"
import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_DIFF } from "./roll-part-diff.mjs"
import { RollPartSelect } from "./roll-part-select.mjs"
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
@@ -15,14 +17,25 @@ export class RollPartComp extends RollPartSelect {
get name() { return 'Compétences' }
get section() { return ROLLDIALOG_SECTION.COMP }
onReady(rollParts) {
this.rollPartCarac = rollParts.find(it => it.code == PART_CARAC)
this.rollPartDiff = rollParts.find(it => it.code == PART_DIFF)
}
loadRefs(rollData) {
const refs = this.getRefs(rollData)
const selected = this.getSelected(rollData)
const all = this.$getActorComps(rollData)
if (selected.forced) {
refs.all = all.filter(comp => Grammar.equalsInsensitive(comp.label, selected.key))
const selectedComp = selected.key
if (selected.forced && selectedComp) {
refs.all = all.filter(comp => Grammar.equalsInsensitive(comp.label, selectedComp))
if (refs.all.length == 0) {
refs.all = all.filter(comp => Grammar.includesLowerCaseNoAccent(comp.label, selected.key))
if (selected.key && selected.key.length > 0) {
refs.all = all.filter(comp => Grammar.includesLowerCaseNoAccent(comp.label, selectedComp))
}
else {
refs.all = all.filter(comp => comp == SANS_COMPETENCE)
}
}
}
else {
@@ -30,6 +43,11 @@ export class RollPartComp extends RollPartSelect {
}
refs.comps = refs.all
this.$selectComp(rollData)
if (rollData.type.current == PART_COMP && selectedComp) {
const current = this.getCurrent(rollData)
this.rollPartCarac.selectByKey(rollData, current.comp.system.defaut_carac)
this.rollPartDiff.setDiff(rollData, current.comp.system.default_diffLibre)
}
}
choices(refs) { return refs.comps }
@@ -66,6 +84,7 @@ export class RollPartComp extends RollPartSelect {
refs.comps.sort(sorting)
}
this.$selectComp(rollData)
}
prepareContext(rollData) {

View File

@@ -10,7 +10,7 @@ export class RollPartConditions extends RollPart {
settingMin() { return RollPart.settingKey(this, 'min') }
settingMax() { return RollPart.settingKey(this, 'max') }
onReady() {
onReady(rollParts) {
game.settings.register(SYSTEM_RDD, this.settingMin(),
{
name: "Malus maximal de conditions",
@@ -65,12 +65,7 @@ export class RollPartConditions extends RollPart {
async _onRender(rollDialog, context, options) {
const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)
input?.addEventListener("input", e => this.onInputChange(e, rollDialog))
}
onInputChange(event, rollDialog) {
this.getCurrent(rollDialog.rollData).value = parseInt(event.currentTarget.value)
rollDialog.render()
input?.addEventListener("input", e => this.onNumericInputChange(e, rollDialog))
}
}

View File

@@ -4,20 +4,22 @@ import { ROLL_TYPE_CUISINE } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP } from "./roll-part-comp.mjs"
import { RollPartSelect } from "./roll-part-select.mjs"
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
export const PART_CUISINE = "cuisine"
export class RollPartCuisine extends RollPartSelect {
onReady() {
onReady(rollParts) {
foundry.applications.handlebars.loadTemplates({ 'roll-oeuvre-recettecuisine': `systems/foundryvtt-reve-de-dragon/templates/roll/roll-oeuvre-recettecuisine.hbs` })
}
get code() { return PART_CUISINE }
get section() { return ROLLDIALOG_SECTION.CHOIX }
get rollTypes() { return [ROLL_TYPE_CUISINE] }
isValid(rollData) { return rollData.active.actor.isPersonnage() }
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_CUISINE) }
visible(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_CUISINE) }
restore(rollData) {
super.restore(rollData)
@@ -148,12 +150,13 @@ export class RollPartCuisine extends RollPartSelect {
this.$selectPreparation(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.render()
})
checkboxFabriquer?.addEventListener("change", e => {
current.fabriquer = e.currentTarget.checked
})
inputDiff?.addEventListener("change", e => {
current.value = parseInt(e.currentTarget.value)
rollDialog.render()
})
inputProportions?.addEventListener("change", e => {
current.proportions = parseInt(e.currentTarget.value)

View File

@@ -1,4 +1,5 @@
import { ITEM_TYPES, RDD_CONFIG } from "../constants.js"
import { Distance } from "../combat/distance.mjs"
import { ITEM_TYPES } from "../constants.js"
import { ATTAQUE_TYPE, RdDItemArme } from "../item/arme.js"
import { CARACS } from "../rdd-carac.js"
import { DIFF, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs"
@@ -7,7 +8,7 @@ import { PART_COMP } from "./roll-part-comp.mjs"
import { PART_DIFF } from "./roll-part-diff.mjs"
import { RollPartSelect } from "./roll-part-select.mjs"
import { PART_SIGN } from "./roll-part-sign.mjs"
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
export const PART_DEFENSE = 'defense'
@@ -16,56 +17,67 @@ export class RollPartDefense extends RollPartSelect {
get code() { return PART_DEFENSE }
get section() { return ROLLDIALOG_SECTION.CHOIX }
isValid(rollData) { return rollData.attackerRoll != undefined }
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_DEFENSE) }
static getDiffAttaque(attackerRoll) {
// TODO: rollDataV2?
return attackerRoll.diffLibre;
}
get rollTypes() { return [ROLL_TYPE_DEFENSE] }
isValid(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_DEFENSE) && rollData.attackerRoll != undefined }
visible(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_DEFENSE) && rollData.attackerRoll != undefined }
loadRefs(rollData) {
const refs = this.getRefs(rollData)
const attackerRoll = rollData.attackerRoll
const defenseur = rollData.active.actor
refs.isDistance = [ATTAQUE_TYPE.TIR, ATTAQUE_TYPE.LANCER].find(it => it == attackerRoll?.main)
refs.distance = rollData.attackerRoll.current?.attaque?.distance
const isEmpoignade = attackerRoll.dmg.isEmpoignade
const isEmpoignadeEnCours = isEmpoignade && defenseur.itemTypes[ITEM_TYPES.empoignade].find(it =>
[it.system.empoigneurid, it.system.empoigneid].includes(rollData.ids.opponentId) &&
it.system.pointsemp != 0)
const esquives = (refs.isDistance == ATTAQUE_TYPE.TIR || isEmpoignadeEnCours)
const esquives = (refs.distance?.typeAttaque == ATTAQUE_TYPE.TIR || isEmpoignadeEnCours)
? []
: defenseur.getCompetencesEsquive()
const parades = isEmpoignade
? [RdDItemArme.empoignade(defenseur)]
: defenseur.items.filter(it => it.isParade() && (!refs.isDistance || it.isBouclier()))
: this.$getParades(defenseur, attackerRoll, refs.distance)
refs.defenses = [
...esquives.map(it => RollPartDefense.$extractEsquive(it, defenseur)),
...parades.map(it => RollPartDefense.$extractParade(it, attackerRoll?.arme, defenseur))
...esquives.map(it => RollPartDefense.$extractEsquive(it, defenseur, attackerRoll)),
...parades.map(it => RollPartDefense.$extractParade(it, defenseur, attackerRoll))
]
this.$selectDefense(rollData)
}
static $extractEsquive(esquive, defenseur) {
return {
$getParades(defenseur, attackerRoll, distance) {
const parades = defenseur.items.filter(it => it.isParade() && (!distance || it.isBouclier()))
const armeAttaque = attackerRoll?.current?.attaque?.arme
return armeAttaque
? parades.filter(armeDefense => RdDItemArme.defenseArmeParade(armeAttaque, armeDefense) != 'impossible')
: parades
}
static $extractEsquive(esquive, defenseur, attackerRoll) {
const defense = {
key: esquive.id,
label: esquive.name,
img: esquive.img,
// TODO: carac pour créatures
// TODO: carac pour créatures à vérifier
carac: defenseur.isPersonnage() ? CARACS.DEROBEE : esquive.name,
verb: "esquive",
comp: esquive,
isEsquive: true
}
if (attackerRoll.current?.attaque?.distance) {
defense.distance = {
ajustementDefense: Distance.ajustementDefense(attackerRoll.current.attaque),
}
}
return defense
}
static $extractParade(armeDefense, armeAttaque, defenseur) {
static $extractParade(armeDefense, defenseur, attackerRoll) {
const armeAttaque = attackerRoll?.arme
const comp = (ITEM_TYPES.competencecreature == armeDefense.type)
? armeDefense
: defenseur.getCompetence(armeDefense.system.competence)
return {
const defense = {
key: armeDefense.id,
label: 'Parade ' + armeDefense.name,
img: armeDefense.img,
@@ -78,6 +90,13 @@ export class RollPartDefense extends RollPartSelect {
typeParade: armeAttaque ? RdDItemArme.defenseArmeParade(armeDefense, armeAttaque) : 'norm',
isEsquive: false
}
if (attackerRoll.current?.attaque?.distance) {
defense.distance = {
ajustementBouclier: Distance.ajustementBouclier(armeDefense),
ajustementDefense: Distance.ajustementDefense(attackerRoll.current.attaque),
}
}
return defense
}
prepareContext(rollData) {
@@ -107,38 +126,42 @@ export class RollPartDefense extends RollPartSelect {
impactOtherPart(part, rollData) {
if (this.visible(rollData)) {
const refs = this.getRefs(rollData)
const current = this.getCurrent(rollData)
switch (part.code) {
case PART_CARAC: return part.filterCaracs(rollData, [current.carac])
case PART_COMP: return part.filterComps(rollData, [current.comp?.name])
case PART_CARAC: return part.filterCaracs(rollData, refs.defenses.length > 0 ? [current.carac] : ['impossible'])
case PART_COMP: return part.filterComps(rollData, refs.defenses.length > 0 ? [current.comp?.name] : ['impossible'])
case PART_DIFF: return part.setDiff(rollData, this.getDiffDefense(rollData))
case PART_SIGN: return part.setArme(rollData, this.isArmeDisparate(rollData), current.forceRequise)
case PART_SIGN: return part.setArme(rollData, this.getArmeDisparate(rollData), current.forceRequise)
}
}
return undefined
}
isArmeDisparate(rollData) {
getArmeDisparate(rollData) {
const armeDefense = this.getCurrent(rollData).arme
if (armeDefense) {
const armeAttaque = rollData.attackerRoll?.current.attaque.arme
return RdDItemArme.defenseArmeParade(armeAttaque, armeDefense) == 'sign'
return RdDItemArme.defenseArmeParade(armeAttaque, armeDefense)
}
return false
return 'norm'
}
getDiffDefense(rollData) {
const refs = this.getRefs(rollData)
if (refs.isDistance || !rollData.attackerRoll) {
// TODO: Déterminer la difficulté de parade
return { diff: 0, type: DIFF.LIBRE }
if (refs.distance) {
const current = this.getCurrent(rollData)
const diff = (current.distance?.ajustementBouclier?.value ?? 0)
+ (current.distance?.ajustementDefense?.value ?? 0)
return { diff: diff, type: DIFF.DEFENSE }
}
else {
if (rollData.attackerRoll) {
const attackerRoll = rollData.attackerRoll
const diff = attackerRoll.v2
? attackerRoll.selected.diff.value
: attackerRoll.diff
return { diff: diff ?? 0, type: DIFF.DEFENSE }
}
return { diff: 0, type: DIFF.LIBRE }
}
}

View File

@@ -32,7 +32,7 @@ export class RollPartDiff extends RollPart {
}
visible(rollData) {
if (EXCLUDED_ROLL_TYPES.includes(rollData.type.current)) {
if (EXCLUDED_ROLL_TYPES.includes(rollData.type.current) || rollData.type.appreciation) {
return false
}
const current = this.getCurrent(rollData)
@@ -73,12 +73,7 @@ export class RollPartDiff extends RollPart {
async _onRender(rollDialog, context, options) {
const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)
input?.addEventListener("input", e => this.onInputChange(e, rollDialog))
}
onInputChange(event, rollDialog) {
this.getCurrent(rollDialog.rollData).value = parseInt(event.currentTarget.value)
rollDialog.render()
input?.addEventListener("input", e => this.onNumericInputChange(e, rollDialog))
}
}

View File

@@ -3,6 +3,7 @@ import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs"
import { PART_ATTAQUE } from "./roll-part-attaque.mjs"
import { RollPartCheckbox } from "./roll-part-checkbox.mjs"
import { PART_DEFENSE } from "./roll-part-defense.mjs"
import { RollPart } from "./roll-part.mjs"
const ECAILLES = "ecailles"
@@ -10,8 +11,9 @@ export class RollPartEcailles extends RollPartCheckbox {
get code() { return ECAILLES }
get rollTypes() { return [ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE] }
isValid(rollData) {
return this.isRollType(rollData, ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE)
return RollPart.isRollType(rollData, ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE)
}
visible(rollData) {
@@ -25,9 +27,9 @@ export class RollPartEcailles extends RollPartCheckbox {
}
getArme(rollData) {
return this.isRollType(rollData, ROLL_TYPE_ATTAQUE)
return RollPart.isRollType(rollData, ROLL_TYPE_ATTAQUE)
? rollData.current[PART_ATTAQUE]?.arme
: this.isRollType(rollData, ROLL_TYPE_DEFENSE)
: RollPart.isRollType(rollData, ROLL_TYPE_DEFENSE)
? rollData.current[PART_DEFENSE]?.arme
: undefined
}

View File

@@ -1,7 +1,8 @@
import { RDD_CONFIG } from "../constants.js"
import { RdDEmpoignade } from "../rdd-empoignade.js"
import { COMBAT_ROLL_TYPES } from "./roll-constants.mjs"
import { COMBAT_ROLL_TYPES, ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs"
import { RollPartCheckbox } from "./roll-part-checkbox.mjs"
import { RollPart } from "./roll-part.mjs"
const EMPOIGNADE_TAILLE = "empoignade-taille"
@@ -9,6 +10,7 @@ export class RollPartEmpoignadeTaille extends RollPartCheckbox {
get code() { return EMPOIGNADE_TAILLE }
get rollTypes() { return [ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE] }
isValid(rollData) {
return RdDEmpoignade.isCombatantEmpoignade(rollData.ids.actorId, rollData.ids.actorTokenId)
}

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