Compare commits

..

20 Commits

Author SHA1 Message Date
de2c636064 Merge pull request '13.0.8 - Le renouveau d'Illysis' (#769) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
All checks were successful
Release Creation / build (release) Successful in 1m37s
Reviewed-on: #769
2025-09-19 23:35:53 +02:00
1ff32697f4 Nouvelle fenêtre de jets de dés 2025-09-19 22:43:49 +02:00
652c435833 Préparation roll-dialog attaques
Les attaques ne sont plus des armes modifiées
2025-09-18 02:08:10 +02:00
74c1f33427 RdDItemArme pour les armes
résolution de souci de dépendance circulaire causée par RdDCombat
2025-09-18 02:08:10 +02:00
0c6caffde3 small items cleanup
Préparation pour retravailler les armes afin de gérer
les attaques dans la nouvelle fenêtre de jets
2025-09-18 02:08:10 +02:00
dc63041682 Fix style sidebar
Perdu depuis la v13 (ou avant)
2025-09-18 02:08:10 +02:00
f572b1c4e1 Fix liste des états dans header
Fix v13
2025-09-18 02:08:10 +02:00
1d63cd54fe Merge pull request '13.0.7 - Sous le signe d'Illysis' (#768) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
All checks were successful
Release Creation / build (release) Successful in 2m23s
Reviewed-on: #768
2025-09-12 20:56:24 +02:00
15e6127e02 Fix effets TMR A0 2025-09-12 18:57:34 +02:00
afd8c2ac80 Migration niveau oeuvres
Passage du niveau à une valeur numérique
2025-09-12 18:56:17 +02:00
18de904849 Affichage des signes d'heure
Présentation en ligne pour fenêtre d'astrologie.
Pourra être utilisée là où on affiche des heures (méditations)
2025-09-12 18:54:47 +02:00
cb48c960c2 appel moral sur double significative
Lors d'un appel au moral avcec un facteur de significative recquis,
vérifier la réussite effective (en utitisant la bnonne fraction du
score) pour déterminer la perte de moral
2025-09-12 18:53:40 +02:00
bd082248d9 Correction de tooltips (v13)
Sur les ajustements, les tooltips sont visibles
2025-09-12 18:52:11 +02:00
df9df90ccb Init premier round 2025-09-12 18:47:41 +02:00
0456221cf7 Merge pull request 'Fix commerces' (#767) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
All checks were successful
Release Creation / build (release) Successful in 5m16s
Reviewed-on: #767
2025-09-02 00:19:24 +02:00
583b4ff003 Fix commerces 2025-08-24 14:57:01 +02:00
b4ac906802 Merge pull request 'v13.0.6' (#766) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
Reviewed-on: #766
2025-08-03 23:35:05 +02:00
395c7a4cc3 Fix boutons feuille simplifiée 2025-08-03 22:48:01 +02:00
27bc07f64a Soins depuis les tokens 2025-08-03 22:48:01 +02:00
2f3ec7bab0 Upadte changelog et normalisation markdown 2025-07-17 07:44:58 +02:00
169 changed files with 5339 additions and 1863 deletions

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><g class="" transform="translate(0,0)" style=""><path d="m214.02 19.115-.02.06a433.415 433.415 0 0 1 106.393 58.446L368.02 158.4C292.254 72.063 181.72 20.678 64.66 20.604c-14.96-.01-30.027.834-45.14 2.535v18.8c108.174-12.774 213.91 21.292 293.527 88.554l42.314 97.416C290.887 132.486 182.425 73.885 66.395 73.21a349.119 349.119 0 0 0-46.879 2.906v18.85c98.998-13.552 196.12 18.532 267.11 82.264l30.708 87.82c-53.922-85.58-148.482-138.656-249.986-139.69a297.451 297.451 0 0 0-47.83 3.398v18.914c93.33-15.18 185.38 18.05 247.677 83.27l20.694 83.917C246.555 230.42 160.67 176.716 67.7 175.423a248.202 248.202 0 0 0-48.182 4.06v19.036c89.513-17.794 178.655 19.16 230.357 89.468l4.62 73.348c-28.973-83.013-107.888-136.692-193.257-135.87a201.938 201.938 0 0 0-41.72 4.78v19.188c77.22-18.904 155.333 13.983 197.095 77.14l5.873 57.49c23.33-6.283 47.534-13.218 68.727-20.873 19.194-6.93 35.884-14.525 46.596-22.038 5.354-3.756 9.142-7.478 11.174-10.574 2.033-3.096 2.47-5.184 2.098-7.59l-1.252-8.123 137.074-39.556C446.897 159.92 363.67 69.964 260.654 19.114H214.02zm278.86 273.922-40.196 11.6c1.63 18.66-4.666 36.567-16.397 52.043-14.18 18.707-35.934 34.627-62.363 48.257-45.23 23.33-104.45 39.877-164.397 47.97l4.38 16.35c68.63-7.66 143.34-22.038 198.17-48.538 30.517-14.75 54.633-33.123 68.722-55.33 12.74-20.084 17.775-43.384 12.08-72.353zm-58.513 16.885-65.027 18.765c-.736 4.345-2.345 8.51-4.733 12.147-3.925 5.98-9.462 10.986-16.068 15.62-13.213 9.266-30.996 17.098-50.978 24.316-31.927 11.53-68.41 20.998-99.558 29.134l6.644 24.79c59.027-7.79 117.64-24.153 160.71-46.366 24.828-12.805 44.388-27.573 56.037-42.94 8.804-11.614 13.283-23.135 12.972-35.466zm-261.754 77.43-33.033 8.85 8.197 30.59c10.812 3.95 18.623 14.38 18.623 26.485 0 6.87-2.52 13.2-6.673 18.114l4.716 17.6 33.034-8.85-24.864-92.788zM138.22 443.79c-1.49 0-2.88.33-4.12.91l-75.6 20.255a30.49 30.49 0 0 1 4.625 16.14c0 .67-.03 1.33-.072 1.987l75.96-20.352c4.96-.386 8.698-4.37 8.698-9.453 0-5.35-4.138-9.488-9.49-9.488zM32.327 468.985c-6.798 0-12.11 5.312-12.11 12.11 0 6.798 5.312 12.11 12.11 12.11 6.798 0 12.111-5.312 12.111-12.11 0-6.798-5.313-12.11-12.11-12.11z" fill="#fff" fill-opacity="1"></path></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

1
assets/actions/comp.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><g class="" transform="translate(0,0)" style=""><path d="M119.1 25v.1c-25 3.2-47.1 32-47.1 68.8 0 20.4 7.1 38.4 17.5 50.9L99.7 157 84 159.9c-13.7 2.6-23.8 9.9-32.2 21.5-8.5 11.5-14.9 27.5-19.4 45.8-8.2 33.6-9.9 74.7-10.1 110.5h44l11.9 158.4h96.3L185 337.7h41.9c0-36.2-.3-77.8-7.8-111.7-4-18.5-10.2-34.4-18.7-45.9-8.6-11.4-19.2-18.7-34.5-21l-16-2.5L160 144c10-12.5 16.7-30.2 16.7-50.1 0-39.2-24.8-68.8-52.4-68.8-2.9 0-4.7-.1-5.2-.1zM440 33c-17.2 0-31 13.77-31 31s13.8 31 31 31 31-13.77 31-31-13.8-31-31-31zM311 55v48H208v18h103v158h-55v18h55v110H208v18h103v32h80.8c-.5-2.9-.8-5.9-.8-9 0-3.1.3-6.1.8-9H329V297h62.8c-.5-2.9-.8-5.9-.8-9 0-3.1.3-6.1.8-9H329V73h62.8c-.5-2.92-.8-5.93-.8-9 0-3.07.3-6.08.8-9H311zm129 202c-17.2 0-31 13.8-31 31s13.8 31 31 31 31-13.8 31-31-13.8-31-31-31zm0 160c-17.2 0-31 13.8-31 31s13.8 31 31 31 31-13.8 31-31-13.8-31-31-31z" fill="#fff" fill-opacity="1"></path></g></svg>

After

Width:  |  Height:  |  Size: 996 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><g class="" transform="translate(0,0)" style=""><path d="M80 32c-64 256 48 416 176 464 128-48 240-208 176-464-112 32-240 32-352 0zm99.3 52.9c14.7 27.9 40.1 26.4 65 26.4l53.9 1.5 7.8 25 77.1 10.3 3.5 49.9c-27.9 7.4-83.7 5.9-83.8 17.7-.2 20.6 36.3 16.2 78.1 5.9L356.7 276l-61.4 4.4c3.8 46.4-1.2 77.6-35.6 110.7l-21.9-55.3c-12.6 22.6-30 38.8-57.3 41.4 10.6-26 19.1-46.7 9.7-76.3-13.5 13.3-35.1 18.7-64.8 16.7 31.6-49 48.3-101.9 62.1-151.9l-23.2-20.6c-6.6-23.5-1.3-44.1 15-60.2z" fill="#fff" fill-opacity="1"></path></g></svg>

After

Width:  |  Height:  |  Size: 621 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><g class="" transform="translate(0,0)" style=""><path d="M261.563 64.28A191.758 191.758 0 0 0 64.25 256a191.758 191.758 0 1 0 383.5 0A191.758 191.758 0 0 0 261.562 64.28zm-4.625 9.126 8.937 5.156v10.313l-8.938 5.156-8.906-5.155V78.562l8.907-5.156zm3.53 29.25A153.407 153.407 0 0 1 409.407 256a153.407 153.407 0 0 1-306.812 0A153.407 153.407 0 0 1 260.47 102.656zm-11.53 20.03a133.607 133.607 0 0 0-65.157 20.908V368.22a133.607 133.607 0 0 0 65.157 21.092V122.688zm17.687.314v266.125a133.607 133.607 0 0 0 63.438-22.03V145a133.607 133.607 0 0 0-63.438-22zm-100.5 34.344A133.607 133.607 0 0 0 122.405 256a133.607 133.607 0 0 0 43.72 98.78V157.345zm-60.72 1.625 8.907 5.155v10.28l-8.906 5.157-8.937-5.156v-10.28l8.936-5.157zm300.5 0 8.94 5.155v10.28l-8.94 5.157-8.905-5.156v-10.28l8.906-5.157zm-58.155.093V353.03A133.607 133.607 0 0 0 389.594 256a133.607 133.607 0 0 0-41.844-96.938zm57.813 173.125 8.937 5.156v10.312l-8.938 5.156-8.906-5.156v-10.312l8.906-5.156zm-299.813.718 8.938 5.156v10.313l-8.938 5.156-8.938-5.155v-10.313l8.938-5.156zm149.906 85.188 8.938 5.156v10.313l-8.938 5.156-8.906-5.158v-10.31l8.906-5.156z" fill="#fff" fill-opacity="1"></path></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

66
assets/actions/jeu.svg Normal file
View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 310.12469 310.12469"
version="1.1"
id="svg6"
sodipodi:docname="jeu.svg"
width="310.12469"
height="310.12469"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2532"
inkscape:window-height="1492"
id="namedview8"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="1.4355469"
inkscape:cx="155.06205"
inkscape:cy="142.25079"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg6" />
<g
class=""
transform="translate(-100.93795,-121.74921)"
id="g4">
<path
d="m 477.518,181.966 a 25,25 0 0 1 -34.91,23 l -62.29,150.26 h -248.92 l -62.24,-150.19 a 25,25 0 1 1 9.73,-7.29 l 87,71.2 20.92,-126.4 a 25,25 0 1 1 14.7,-1.85 l 54.31,117 54.42,-117.3 a 25,25 0 1 1 14.58,2.08 l 20.93,126.42 87.26,-71.3 a 25,25 0 1 1 44.51,-15.63 z m -71.66,241.25 h -300 v 60 h 300 z m -27.75,-52 h -244.22 v 36 h 244.22 z"
fill="#ffffff"
fill-opacity="1"
transform="matrix(0.7,0,0,0.7,76.8,76.8)"
id="path2" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 512 512"
version="1.1"
id="svg8"
sodipodi:docname="meditation1.svg"
width="512"
height="512"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata14">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs12" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:window-width="3840"
inkscape:window-height="2054"
id="namedview10"
showgrid="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="1.4355469"
inkscape:cx="254.56378"
inkscape:cy="255.99978"
inkscape:window-x="-11"
inkscape:window-y="-11"
inkscape:window-maximized="1"
inkscape:current-layer="svg8">
<inkscape:grid
type="xygrid"
id="grid856" />
</sodipodi:namedview>
<path
id="polygon2"
style="fill:#ffffff;fill-opacity:1;stroke:none"
d="M 256,0 0,256 256,512 512,256 Z m 5.11719,62.361328 c 8.239,0 15.89463,4.297288 21.83203,12.054688 5.2108,6.811 8.83798,16.231192 9.64648,26.841794 -8.4868,-3.970403 -17.26742,-6.37191 -26.14062,-7.13281 v 12.81836 c 8.5484,0.9429 17.03537,3.85822 25.48437,8.64062 -1.442,8.41469 -4.67333,15.84043 -8.99023,21.48243 -5.9367,7.7574 -13.59443,12.05468 -21.83203,12.05468 -8.2376,0 -15.8726,-4.29728 -21.8086,-12.05468 -4.452,-5.8184 -7.76497,-13.52864 -9.14257,-22.26953 7.8043,-4.21541 15.53348,-6.75681 23.20898,-7.72071 V 94.191406 c -7.938,0.763 -15.87192,2.852576 -23.66992,6.300784 0.9261,-10.297007 4.51857,-19.430374 9.60547,-26.076174 5.936,-7.7581 13.57099,-12.052735 21.80859,-12.052735 z M 228.50391,144.4375 c 0.14,0.1883 0.27391,0.38286 0.41601,0.56836 7.8876,10.3082 19.34232,17.19336 32.19922,17.19336 12.8569,0 24.31162,-6.88586 32.19922,-17.19336 0.1421,-0.1862 0.27797,-0.37936 0.41797,-0.56836 7.2765,3.3453 12.81763,7.79108 15.76953,12.86328 h 0.0449 l 29.11524,45.10547 35.48046,-15.37891 c 20.5632,-11.2833 43.10446,16.80074 21.43946,29.18164 l -66.12891,30.84571 -25.74609,-33.90821 c -11.6662,23.2505 -11.80448,46.48779 6.66992,69.73829 37.3275,-3.0275 65.31156,3.90026 69.47656,19.44726 3.4104,12.7316 -9.91357,28.42679 -33.35937,42.45899 l -66.10743,-21.9629 33.66602,-11.17773 -4.11328,-12.4043 -50.29102,16.69141 -50.26757,-16.69141 -4.11133,12.4043 126.1289,41.89063 15.53321,37.60351 -64.44532,-20.10351 0.0234,-0.22071 c -0.2989,-0.0168 -0.5782,-0.0463 -0.875,-0.0645 l -0.30664,-0.0879 h -1.09375 c -43.1116,-2.7132 -70.90445,-9.13273 -109.87695,-29.64063 -19.6938,-13.027 -30.49667,-27.09126 -27.38867,-38.69726 h -0.0215 c 3.4755,-12.9682 23.51598,-19.95189 51.73438,-20.14649 5.3179,-0.0364 10.93654,0.18537 16.77734,0.63477 19.418,-23.6082 20.76969,-47.21649 7.67969,-70.80859 l -26.6211,35.04296 -66.1289,-30.84375 c -21.665,-12.3816 0.87304,-40.46424 21.43554,-29.18164 l 35.46094,15.37891 29.13672,-45.10547 0.26172,0.0664 c 2.9421,-5.1016 8.50701,-9.56969 15.81641,-12.92969 z m -44.58008,217.70117 c 12.7582,5.6602 24.87218,9.90172 37.20898,13.10352 l -48.91406,15.24609 z" />
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><g class="" transform="translate(2,-1)" style=""><path d="m375.2 23.61-12.7 12.7 24.5 24.5c.5-1.2 1-2.3 1.5-3.5 2.4-6.6 4.1-12.4 4.9-15.5zm33.3 30.5c-.9 3-1.9 5.9-3.3 9.6-4 10.8-9.1 23.4-20.2 30.4-4 2.4-8.1 2.6-11.2 2.3-3.1-.3-5.6-1.1-7.5-1.6-1.7-.4-2.6-.6-3.2-.7-.6.9-1.2 2.2-1.6 4.5-.8 3.19-1 7.49-.8 11.59.1 6 .7 10.5 1.2 13.1l26.8 26.8c2.6.4 7.1 1 13 1.2 7.5.1 14.3-1.8 16-2.7-.1-.8-.2-1.4-.6-2.9-.5-2-1.3-4.5-1.7-7.6-.3-3.1 0-7.3 2.3-11.2 7-11.1 19.6-16.2 30.5-20.3 3.6-1.4 6.6-2.2 9.6-3.1l-16.4-32.89zm-67.2 3.4-12.7 12.7 17.4 17.5c1.3-2.9 3-5.6 5.6-7.9 2.5-2.2 5.6-3.3 8.3-3.7zm128.9 60.99c-3.2.8-9.1 2.4-15.7 5-1.1.4-2.2.8-3.4 1.3l24.6 24.6 12.7-12.7zm-120.7 17.9L217.4 262.3l9.8 9.8 129-129zm86.3 15.5c-.4 2.8-1.5 6-3.8 8.5s-4.8 4.3-7.5 5.6l17.3 17.3 12.7-12.7zm-66.9 3.9L240 284.9l9.7 9.6 125.9-132zm-226.3 94.5c-30.4 0-60.87 11.6-84.13 34.9-46.53 46.5-46.53 121.7 0 168.3C105 500 180.2 500 226.8 453.5c35.8-35.9 43.9-88.5 24.7-132.2L156.8 416l14.9 14.9-12.8 12.7-90.46-90.5 12.73-12.7 14.75 14.7 94.78-94.7c-15.3-6.8-31.7-10.1-48.1-10.1zm60.6 23.2-94.5 94.4 11.3 11.3 94.5-94.4zm24 24L132.7 392l11.2 11.2 94.6-94.4z" fill="#fff" fill-opacity="1"></path></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

65
assets/actions/sort.svg Normal file
View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="66.69709mm"
height="66.69709mm"
viewBox="0 0 378.10574 378.10571"
version="1.1"
id="svg3"
sodipodi:docname="sort.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata9">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs7" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="3840"
inkscape:window-height="2054"
id="namedview5"
showgrid="false"
inkscape:zoom="3.887601"
inkscape:cx="72.254869"
inkscape:cy="97.300114"
inkscape:window-x="-11"
inkscape:window-y="-11"
inkscape:window-maximized="1"
inkscape:current-layer="svg3"
inkscape:document-rotation="0"
inkscape:snap-text-baseline="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<path
id="Sélection #2"
fill="none"
stroke="black"
stroke-width="1"
d="M 189.05286,0 378.10571,189.05286 189.05285,378.10571 0,189.05286 Z m 98.94184,241.93328 c -0.88,-10.41 -2.89,-10.17 -9.87,-16.75 l -5.39,-5.72 c -2.61,-2.12 -6.9,-3.02 -8.72,-5.91 -1.19,-1.9 -0.91,-4.46 -1.28,-6.62 -3.40308,-4.90559 -2.01923,-20.20245 -2.01923,-26.63889 3.88586,-9.60746 4.36923,-1.69111 7.45923,-14.36111 0.62,-2.55 2.32,-6.14 1.21,-8.69 -1.07,-2.43 -3.44,-2.03 -6.71,-5.17 -5.66937,-7.30653 -11.39498,-14.88252 -18.68,-20.92 -23.49144,-15.67176 -34.12005,-20.68725 -60,-20.32 -8.54383,0.23148 -13.2432,0.66798 -20,2.68 -19.05,6.09 -27.58,11.85 -41.76999,25.79 -8.08,7.96 -7.17,10.3 -10.91,14.41 -3.1,3.4 -6.12,3.44 -6.73,7.27 -0.64,1.83 -0.09,3.98 0,5.78 1.91418,8.65633 2.50026,3.00305 7.73101,9.8295 1.38405,9.6854 0.3222,25.26042 -0.70608,33.05113 -2.53556,2.89228 -2.29493,5.91937 -3.63493,7.97937 -1.62,2.49 -4.35,2.16 -7.77,5.03 -5.170004,4.32 -4.470004,8.06 -13.210004,13.28 1.78,5.5 4.63,5.91 10,6 z M 195.6316,118.20709 c 11.22808,5.82176 1.31866,21.02928 -11.27386,31.1911 13.0336,5.31132 -0.79998,6.64062 23.09132,6.48796 l 32.86359,-0.54563 13.5005,1.22254 7.27084,3.68304 c -4.13,5.49 -2.71929,1.23718 -2.08929,8.68718 h -4 c -0.28,-1.68 -0.54282,-4.85331 -1.87282,-6.17331 -3.32127,-0.17387 -9.61514,-0.5831 -13.55025,0.47743 -0.17052,3.22972 -0.29693,4.01588 -0.57693,5.69588 l -3.40923,-0.34102 c -0.28,-1.68 0.27564,-3.83025 -1.05436,-5.15025 -3.7305,-0.17387 -10.29718,-0.7195 -13.48204,0.40923 -1.33,1.32 -0.77437,3.40204 -1.05437,5.08204 h -3 c -0.28,-1.68 0.071,-3.08 -0.91796,-5.08204 -2.83922,-1.53335 -14.39204,-0.93796 -18.08204,-0.91796 -1.96,0.01 -5.02,-0.11 -6.68,1.02 -0.19823,6.27508 -0.4088,8.38327 1.52129,9.86916 l 20.15871,0.0399 v 37.07089 h -19.09 c 0.0887,-5.45486 2.17,-22.09 0,-25.77 -2.24,-3.53 -10.37,-4.58 -13.31,-1.63 -0.59765,14.41964 -0.37159,20.85123 -0.92619,27.34486 -16.5374,0 -13.4074,0.42 -16.5374,0 l -0.13641,-21.94486 c -0.0284,-4.56991 -0.5617,-9.93269 1.12488,-14.46674 3.57532,-2.18241 14.40143,0.2341 20.38143,-0.7259 1.06669,-3.31458 1.12908,-6.5781 0.80651,-10.05451 -2.74793,-0.83105 -4.76282,-0.70285 -7.31282,-0.75285 h -11 c -7.39,0.05 -9.43418,2.79797 -7.61418,10.68797 l -6.48228,0.24114 c 0.72,-2.06 1.97646,-7.02474 0.81646,-9.16474 -1.7,-3.14 -11.93127,-2.75719 -14.21127,-0.43719 -2.03,2.07 -1.8049,7.64421 -1.24493,10.08421 l -7.37013,0.12387 c -0.24405,12.94493 0.23633,18.13752 0.10633,29.28752 -0.09,7.42 0.28,6.88722 -7.99999,7.17722 v -28 c 0,-2.48 0.22,-6.59 -1.17,-8.69 -1.62,-2.42 -4.26,-2.22 -6.83,-2.31 2.73,-7.8 6.25917,-8.9 -1.27083,-9 10.53404,-8.39725 16.12632,-16.70355 22.85717,-22.49183 5.05278,-4.9362 12.06169,-10.2231 15.11169,-11.61765 14.97984,-6.56268 20.63207,-10.69702 43.93886,-10.61671 z m -73.26379,44.49619 c -0.79548,4.04536 -1.9331,12.40663 2.6469,12.48663 10.50353,0.43469 11.50999,-8.2279 8.90999,-11.7879 -1.43,-1.96 -9.22689,-0.64873 -11.55689,-0.69873 z m 19.62689,11.59316 9.01278,-0.14468 0.91722,5.78152 c 0.10638,11.6222 0,0 0.0146,31.52202 -8.59422,-0.32911 -7.4946,-0.52202 -9.9446,-0.52202 z m 80.95177,-0.77164 8.14469,0.22835 -0.0965,36.18013 h -8 z m 19.38582,0.5305 7.6014,-0.33759 0.061,36.21557 h -8 z m -129.12528,49.01235 11.33333,-0.31493 45.72718,-0.54563 59.09028,-0.81845 33.54662,-0.27282 c 7.10809,1.39089 4.61048,5.28283 13.46463,11.36941 -49.05198,-0.38776 -122.72138,-0.48241 -173.42548,-0.8649 z"
style="fill:#d6d2d0;fill-opacity:1;stroke:none"
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccscccccccccccccsccccccccccccccccccccccccccccccccccc" />
</svg>

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><g class="" transform="translate(0,-28)" 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(76.8, 76.8) scale(0.7, 0.7) 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;"><g class="" transform="translate(0,-28)" style=""><path d="M332.031 66.13c-28.807-.01-55.439 14.149-67.88 40.65 20.79 1.744 16 55.07 16 55.07-11.814 16.687-24.73 33.186-36.589 50.146 0 0-99.046 132.283-178.378 168.025-28.049 22.593-33.305 36.532-44.137 52.649-4.877 9.54 9.257 14.324 11.701 13.2 22.726-10.461 25.176-20.866 47.07-35.675 12.805-5.026 23.839-15.9 31.854-11.049 34.962 20.86 107.556 44.28 118.271 38.706 17.857-9.263-5.78-43.585 16.174-89.057 31.97-3.352 58.916-.885 88.332-12.094 3.483 50.279 10.106 54.59 6.766 107.092l71.2 1.045.698-14.61-41.814-11.105c11.528-56.054 11.816-78.996 4.672-127.996-.956-6.622-53.746-8.275-81.012-3.79 24.449-24.202 40.274-45.24 47.506-68.44l.027.189c7.637 15.923 30.083 33.958 35.336 37.125 27.704 11.048 38.214 7.982 62.955 3.887 4.907-.784 27.47 24.537 44.807 9.597 2.642-20.238 16.522-20.369-4.938-32.71-4.847-2.73-27.063 7.462-31.418 6.898-20.21-2.481-30.954-5.211-58.45-12.703-10.23-13.187-32.676-56.136-55.43-59.744 6.535-14.15 28.226-53.108 73.664-66.237-20.943-26.54-49.925-39.057-76.987-39.068zm82.405 46.722c-46.658 19.516-58.266 50.4-58.266 50.4l9.916 7.644s9.646-4.765 48.35-58.044zm23.04 160.005-4.658 11.418c5.233-.083 10.425.47 15.328 1.608-12.774 30.856-23.938 59.635-28.181 93.094l-.908 7.558 4.863-5.889c20.805-25.671 32.303-55.25 44.95-85.78 4.203 2.656 8.24 5.885 12.071 9.35l4.78-11.374-20.518-8.526-31.767 66.579 24.062-69.713-20.021-8.325z" fill="#fff" fill-opacity="1" transform="translate(76.8, 76.8) scale(0.7, 0.7) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

1
assets/actions/tache.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><g class="" transform="translate(0,0)" style=""><path d="M56.813 18.438c-.47-.005-.938.014-1.407.03-.625.023-1.252.066-1.875.126-7.468.72-14.682 4.148-22.31 11.125-9.985 9.128-12.863 17.66-11.407 27.718 1.455 10.056 8.353 22.236 21.125 34.906 2.895 2.872 6.126 5.737 9.593 8.625 1.27 1.055 2.565 2.13 3.907 3.186a200.62 200.62 0 0 0 3.438 2.656c.232.175.454.358.688.532C74.71 119.38 95.558 131.28 120.25 142.22c159.723 161.31 288.815 297.553 374.594 352.124-51.11-85.624-187.432-214.62-350-375.531-10.23-23.802-21.115-43.71-32.094-59.282 35.46-10.19 82.517-2.294 125.75 40.94 40.243 40.242 52.642 90.776 41.375 128.343 4.89 4.914 9.883 9.913 14.688 14.75 19.07-46.1 4.573-108.895-42.844-156.313-35.694-35.693-75.48-50.324-111.032-50.22-1.147.005-2.3.03-3.438.064-21.844.65-41.957 6.898-58.344 17.187a102.302 102.302 0 0 0-8.312 5.814c1.33 3.094 2.758 5.884 4.406 8.218 1.92 2.72 4.004 4.936 6.906 6.688 2.202-1.717 4.498-3.375 6.938-4.906a88.727 88.727 0 0 1 3.25-1.97c8.196 10.088 15.465 24.624 25.47 47.25-23.907-10.568-38.822-18.04-49.033-27 .024-.03.04-.063.064-.093-.433-.33-.867-.655-1.28-1-.013-.008-.022-.02-.033-.03-11.215-10.375-16.532-22.934-22.31-44.5 5.988 1.605 11.256 3.19 16 4.844a137.13 137.13 0 0 1 26.81-15.875c-9.5-7.738-18.552-11.93-26.686-12.97-1.443-.185-2.87-.3-4.282-.313zM493.28 64.374c-77.985 0-125.587 28.886-146.124 69.406-20.536 40.52-13.994 90.39 9.688 131.407 11.385 19.72 17.807 40.687 19.187 61.22a4329.64 4329.64 0 0 1 18.47 19.187c2.31-29.955-5.072-61.35-21.47-89.75-21.13-36.602-26.155-80.112-9.186-113.594 16.97-33.481 55.94-59.188 129.437-59.188V64.376zM37.907 114.938c-2.894 23.925 6.18 50.21 29.532 73.562l13.218-13.188c-15.97-15.97-23.188-31.833-24.437-46.593-6.646-4.51-12.754-9.102-18.314-13.782zM124.062 277c-24.466-.028-45.04 4.92-61.343 13.656-24.842 13.31-39.363 35.865-40.75 60.47-2.78 49.207 44.38 102.65 140.405 118.28 101.63 16.544 170.303-9.184 205.406-54.062 1.01-1.29 1.988-2.59 2.94-3.906-4.552-4.232-9.148-8.52-13.783-12.875-1.233 1.79-2.52 3.55-3.875 5.28-29.97 38.315-90.355 62.97-187.687 47.126-90.394-14.715-126.796-62.527-124.75-98.783 1.023-18.127 10.982-34.37 30.938-45.062 19.955-10.692 50.267-15.364 90.5-7.47 34.077 6.69 62.938 3.47 85.437-6.936-4.72-4.65-9.49-9.33-14.28-14.064-17.545 6.452-39.89 8.088-67.564 2.656-14.895-2.923-28.778-4.297-41.594-4.312z" fill="#fff" fill-opacity="1"></path></g></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

1
assets/ui/d100.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(201, 201, 201, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite>0<feOffset dx="230" dy="300" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><g class="" transform="translate(-100,0)" style=""><path d="m375.483 251.243-109.98 51.138.213 183.381L477.01 266.346l-86.993-21.81zm-12.736 108.626-5.947 14.699-48.604-8.955 5.007-12.832a141.306 141.306 0 0 0 13.51-11.358 167.184 167.184 0 0 0 16.566-17.517 170.478 170.478 0 0 0 12.606-17.958 115.607 115.607 0 0 0 9.514-17.97l14.068 2.51q-9.37 22.334-30.361 44.43-13.296 13.64-20.645 18.636zM121.603 244.334l-84.71 21.763L246.474 486V302.38l-109.946-51.137zm19.147 50.852a28.72 28.72 0 0 1 24.273 6.802 53.052 53.052 0 0 1 11.226 14.188l-13.081 2.676a28.542 28.542 0 0 0-5.388-7.374q-5.185-4.876-11.262-3.853l-.487.095a6.458 6.458 0 0 0-5.162 4.448c-.856 2.378-.238 5.554 1.796 9.371q4.08 7.6 10.81 9.027a23.785 23.785 0 0 0 8.563-.203l1.867-.344 5.791 10.822q-6.398 1.427-8.23 3.282-3.21 3.14.429 9.93a17.042 17.042 0 0 0 6.089 6.696 10.406 10.406 0 0 0 7.385 1.534l.416-.083q4.757-.964 5.079-4.757c.261-2.57-.655-5.744-2.748-9.514l12.38-2.545a49.247 49.247 0 0 1 4.103 11.226 19.956 19.956 0 0 1-.642 9.383 11.702 11.702 0 0 1-3.96 5.411 19.575 19.575 0 0 1-8.027 3.235l-1.19.214a27.971 27.971 0 0 1-17.494-2.7 32.193 32.193 0 0 1-14.128-14.092q-3.627-6.79-2.604-12.19a8.396 8.396 0 0 1 2.521-4.947h-.071q-1.844.31-7.04-2.497a32.11 32.11 0 0 1-12.916-13.593q-5.245-9.764-3.282-18.398 1.962-8.634 13.676-11zM27.19 248.865l108.78-116.309a7.135 7.135 0 0 1 1.427 0h.154q3.14.345 2.842 3.71a19.36 19.36 0 0 1-3.294 8.1 39.376 39.376 0 0 1-9.728 10.405q-3.912 2.938-15.044 9.514-12.796 7.505-19.55 14.77a92.535 92.535 0 0 0-11.513 14.486l32.907 3.758 8.182-12.963-20.967-2.378a36.415 36.415 0 0 1 4.757-3.83q2.379-1.605 8.444-5.125l6.422-3.747a92.975 92.975 0 0 0 12.903-8.776 61.472 61.472 0 0 0 12.51-14.414q6.84-10.846 6.494-17.957c-.19-3.949-2.105-6.434-5.684-7.505l79.798-85.161-102.097 179.576-5.708 10.06zm367.238-71.974q-3.817-5.458-3.758-8.515c0-2.033 1.19-3.199 3.568-3.448h.57a11.892 11.892 0 0 1 6.91 2.247 29.85 29.85 0 0 1 7.837 8.051q3.687 5.28 3.71 8.397c0 2.093-1.188 3.258-3.496 3.567h-.594a11.75 11.75 0 0 1-6.957-2.378 29.79 29.79 0 0 1-7.79-7.885zm-109.41-141.52 83.948 89.634h-1.189c-.38 0-.975 0-1.463.107q-7.825.892-8.324 6.862-.5 5.97 5.03 13.747a53.778 53.778 0 0 0 6.375 7.374 37.901 37.901 0 0 0 10.144 6.897q-2.117 2.89-.702 7.98a37.283 37.283 0 0 0 5.613 11.096 55.122 55.122 0 0 0 15.223 14.806q8.098 5.268 16.066 4.935.81 0 1.618-.13 8.776-.988 9.228-7.873a16.114 16.114 0 0 0-.463-4.853l58.689 62.686-91.572-22.941-6.1-10.703zm98.22 104.927 2.45 2.617c.451.57.903 1.189 1.355 1.784 1.808 2.592 2.723 4.757 2.723 6.529 0 1.771-1.034 2.782-3.127 3.02h-.512a10.346 10.346 0 0 1-6.077-1.95 22.596 22.596 0 0 1-6.184-6.137c-1.974-2.83-2.937-5.102-2.878-6.814.06-1.713 1.118-2.7 3.187-2.937h.524a10.263 10.263 0 0 1 6.005 1.879 19.147 19.147 0 0 1 2.533 2.01zM255.987 26 137.456 231.026l118.532 55.05 118.604-55.05zm-1.19 208.463q-17.529 0-24.58-12.273-7.053-12.273-7.053-34.988 0-22.714 7.052-35.047 7.052-12.332 24.582-12.344 17.53 0 24.582 12.332 7.052 12.333 7.052 35.047 0 22.715-7.052 34.988-7.053 12.273-24.582 12.285zm10.538-71.807q2.497 7.968 2.497 24.546 0 15.817-2.497 24.201-2.498 8.384-10.537 8.325-8.04 0-10.632-8.325-2.593-8.324-2.593-24.2 0-16.579 2.593-24.547t10.632-7.968q8.015-.012 10.513 7.956z" fill="#fff" fill-opacity="1" filter="url(#shadow-1)" transform="translate(128, 128) scale(0.5, 0.5) rotate(-30, 256, 256) skewX(0) skewY(0)"></path></g></svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><g class="" transform="translate(0,-28)" style=""><path d="M119.436 36c-16.126 0-29.2 17.237-29.2 38.5v363c0 21.263 13.074 38.5 29.2 38.5h275.298c16.126 0 29.198-17.237 29.198-38.5v-363c0-21.263-13.072-38.5-29.198-38.5zm26.369 10.951 11.002 32.856 34.648.312-27.848 20.617 10.41 33.05-28.212-20.114-28.215 20.113L128 100.736 100.152 80.12l34.649-.312zM363.979 161.84c7.127 9.459 12.739 20.689 16.832 32.04 3.8 10.544 6.197 21.211 6.668 31.02-.163 19.015-3.915 23.274-14.557 36.934l-6.703-11.48c-10.85-13.106-30.779-48.4-47.383-43.672-6.521 6.11-8.996 13.37-10.313 20.802 2.898 8.8 4.477 18.43 4.477 28.516 0 15.293-3.615 29.54-9.996 41.416 22.643 4.537 57.927 19.332 57.973 39.223-.27 3.783-1.835 7.68-4.362 10.42-10.743 12.528-36.958 4.125-45.2 10.072.796 6.947 4.112 14.118 4.355 20.174.136 4.36-1.768 10.58-6.508 13.996-5.67 4.087-12.968 4.551-18.52 3.045C279.94 392.226 272 379.649 256 377c-13.544 3.491-22.412 13.87-34.742 17.346-5.552 1.506-12.85 1.042-18.52-3.045-4.74-3.417-6.644-9.636-6.508-13.996-.058-7.142 4.107-13.794 4.356-20.174-15.741-7.788-33.816 1.97-45.201-10.072-2.527-2.74-4.093-6.637-4.362-10.42 6.146-27.341 35.374-34.684 57.973-39.223C202.615 285.54 199 271.293 199 256c0-11.489 2.047-22.385 5.764-32.135-2.357-7.923-3.441-15.988-9.438-22.441-8.758-.925-14.079 6.897-17.842 12.63-11.683 19.5-18.718 30.606-32.88 46.192-16.604-23.4-19.314-49.29-13.157-70.988 6.065-20.331 19.17-38.798 37.926-47.924 21.216-9.766 39.872-10.03 58.885.203 5.163-13.053 10.4-25.65 18.035-36.209 9.625-13.31 23.8-25.631 43.707-25.295 38.8.656 73.993 51.156 73.979 81.807zm-72.22-63.893c-35.759 2.409-44.771 44.746-55.189 71.29l-9.447-7.087c-18.428-12.31-31.076-13.732-49.875-4.63-12.924 6.288-23.701 20.62-28.553 36.882-3.38 11.329-3.765 23.225-.949 33.645 9.45-13.549 15.806-30.08 28.317-39.178 7.486-7.975 26.27-8.498 35.45 3.897 4.838 7.02 7.437 14.54 9.5 22.234h72.165c.592-1.944 1.067-3.762 2.017-6.033 2.956-7.064 7.765-16.266 18.395-19.504 18.09-3.862 32.494 7.106 43.498 18.514 4.517 4.717 8.492 9.696 12.098 14.517-.69-6.798-2.477-14.651-5.31-22.508-13.127-36.707-37.889-51.031-70.386-32.011 2.556-16.423 16.87-35.72 46.25-26.962-9.094-17.135-30.355-42.471-47.98-43.066zM220.644 233c-2.31 6.965-3.643 14.753-3.643 23 0 15.85 4.892 30.032 12.26 39.855C236.628 305.68 245.988 311 256 311s19.372-5.32 26.74-15.145C290.108 286.032 295 271.85 295 256c0-8.247-1.334-16.035-3.643-23zM232 280h48s-8 14-24 14-24-14-24-14zm-11.14 33.566c-13.86 3.34-50.369 8.9-51.842 21.42 9.621 1.947 20.446.838 28.998 2.235 5.993 1.018 12.82 3.323 17.285 9.517 3.375 4.683 3.577 10.103 3.037 14.21-.543 5.89-3.317 10.557-3.975 16.32 15.955-2.59 28.264-17.532 41.637-18.268 16-.702 29.313 17.402 41.637 18.268-.893-5.59-3.262-11.158-3.975-16.32-.54-4.107-.338-9.527 3.037-14.21 4.465-6.194 11.292-8.5 17.285-9.517 9.742-2.229 19.975.396 28.998-2.235-5.77-13.125-39.813-19.454-51.841-21.42C281.665 323.01 269.45 329 256 329c-13.452 0-25.665-5.991-35.14-15.434zm117.122 64.649 28.213 20.113 28.215-20.113L384 411.264l27.848 20.617-34.649.312-11.004 32.856-11.002-32.856-34.648-.312 27.848-20.617z" fill="#fff" fill-opacity="1" transform="translate(76.8, 76.8) scale(0.7, 0.7) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

After

Width:  |  Height:  |  Size: 3.2 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{fill:#DCDCDC;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
.st1{display:none;}
.st2{display:inline;}
</style>
<g id="icon_x5F_sidebar_x5F_chat">
<g>
<g>
<g>
<path class="st0" 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="st1">
<g class="st2">
<g>
<g>
<path class="st0" 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="st0" 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="st0" 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="st1">
<g class="st2">
<g>
<g>
<path class="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st1">
<g class="st2">
<g>
<g>
<path class="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" points="441.11,403.38 441.22,403.67 441,403.48 "/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_item" class="st1">
<g class="st2">
<g>
<g>
<path class="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st1">
<g class="st2">
<g>
<g>
<path class="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st1">
<g class="st2">
<g>
<g>
<path class="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st0" 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="st1">
<g class="st2">
<g>
<g>
<path class="st0" 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="st0" 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="st1">
<g class="st2">
<g>
<g>
<path class="st0" 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="st0" 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="st0" 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="st1">
<g class="st2">
<g>
<g>
<path class="st0" 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="st0" 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;"><g class="" transform="translate(0,-28)" style=""><path d="M211.313 21.094c-51.776 0-98.754 12.252-133.5 32.718C43.066 74.28 19.874 103.78 19.874 137.69c0 33.54 22.692 62.81 56.813 83.25L48.156 327.094l96.97-79.844c20.65 4.58 42.924 7.063 66.186 7.063 51.776 0 98.786-12.252 133.532-32.72 34.746-20.466 57.937-49.997 57.937-83.905s-23.19-63.41-57.936-83.875c-34.746-20.467-81.756-32.72-133.53-32.72zm0 18.687c48.8 0 92.866 11.77 124.03 30.126 31.165 18.357 48.75 42.447 48.75 67.78 0 25.338-17.585 49.457-48.75 67.814-31.164 18.357-75.23 30.125-124.03 30.125S118.445 223.857 87.28 205.5c-31.163-18.357-48.718-42.476-48.718-67.813 0-25.336 17.555-49.424 48.72-67.78C118.445 51.55 162.51 39.78 211.31 39.78zM96.53 89.938v18.688h93.126V89.937H96.53zm111.814 0v18.688h28.094V89.937h-28.094zm46.78 0v18.688h71.97V89.937h-71.97zM96.532 129.844v18.72h29.657v-18.72H96.53zm48.345 0v18.72h65.938v-18.72h-65.938zm84.656 0v18.72h38.095v-18.72H229.53zm56.782 0v18.72h40.782v-18.72h-40.78zM96.532 166.78v18.69h70.874v-18.69H96.53zm89.562 0v18.69h57.03v-18.69h-57.03zm75.72 0-.002 18.69h65.282v-18.69h-65.28zm92.342 90.25c-74.88 0-135.594 41.762-135.594 93.283 0 51.52 60.716 93.28 135.594 93.28 18.23 0 35.623-2.48 51.5-6.968l68.53 51.156-24.873-71.03c24.947-16.918 40.437-40.432 40.437-66.438 0-51.518-60.714-93.28-135.594-93.28zm-70.344 42.345h32.907v18.688H283.81v-18.688zm51.594 0h90.344v18.688h-90.344v-18.688zm-78.97 41.75h78.314v18.688h-78.313v-18.688zm97.002 0h20.968v18.688h-20.97l.002-18.688zm39.656 0h51v18.688h-51v-18.688zm-109.28 39h79.06v18.688h-79.062v-18.688zm97.748 0h44.188v18.688h-44.188v-18.688z" fill="#fff" fill-opacity="1" transform="translate(76.8, 76.8) scale(0.7, 0.7) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 640 640"
version="1.1"
id="svg4"
sodipodi:docname="icon_sidebar_macros.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2666"
inkscape:window-height="1514"
id="namedview6"
showgrid="false"
inkscape:zoom="1.6241359"
inkscape:cx="170.14667"
inkscape:cy="292.89075"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg4"
units="in" />
<path
d="m 378.25,116.16 c -13.6,-3.92 -27.76,4 -31.68,17.6 l -102.4,358.4 c -3.92,13.6 4,27.76 17.6,31.68 13.6,3.92 27.76,-4 31.68,-17.6 l 102.4,-358.4 c 3.92,-13.6 -4,-27.76 -17.6,-31.68 z m 51.68,108.88 c -10,10 -10,26.24 0,36.24 l 58.72,58.72 -58.72,58.72 c -10,10 -10,26.24 0,36.24 10,10 26.24,10 36.24,0 l 76.8,-76.8 c 10,-10 10,-26.24 0,-36.24 l -76.8,-76.8 c -10,-10 -26.24,-10 -36.24,0 z m -219.76,0 c -10,-10 -26.24,-10 -36.24,0 l -76.8,76.8 c -10,10 -10,26.24 0,36.24 l 76.8,76.8 c 10,10 26.24,10 36.24,0 10,-10 10,-26.24 0,-36.24 L 151.45,320 210.09,261.28 c 10,-10 10,-26.24 0,-36.24 z"
id="path2"
style="fill:#ffffff;stroke-width:0.8" />
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

View File

@@ -1,5 +1,36 @@
# 13.0
## 13.0.8 - Le renouveau d'Illysis
- Fix Foundry V13
- Les états sont de nouveau affichés en ligne dans la feuille de personnage
- les icones spécifiques Rêve de Dragon de la barre de droite sont de nouveau utilisées
- Nouvelle fenêtre de jets de dés
- uniquement pour les oeuvres (chant, danse, musique, cuisine,...)
- à activer dans les options avancées
## 13.0.7 - Sous le signe d'Illysis
- Fix Foundry V13
- les tooltips des ajustements sont correctement visible
- correction des affichages des signes d'heures dans la fenêtre d'astrologie
- en cas d'appel au moral lorsqu'une double significative est requise,
le moral est perdu si la réussite est insuffisante
- transformation du niveau des musiques/danses/chants/recettes de cuisine en valeur numérique
- les effets draconiques sur une case inconnue (A0) ne causent plus de problèmes dans les TMRs
## 13.0.6 - Le bandage d'Illysis
- Les soins sont de nouveau disponibles depuis les tokens
- Correction des boutons de la feuille simplifiée
- On peut de nouveau acheter dans les commerces
## 13.0.5
- Export CSV/Scriptarium à nouveau disponible dans les menus d'acteurs
## 13.0.4 - Le long discours d'Illysis
- On peut de nouveau modifier les descriptions
@@ -26,17 +57,21 @@
- Migration vers la version 13 de Foundry
# 12.0
## 12.0.50 - Le sommeil d'Astrobazzarh
- Le don de double rêve n'interrompt plus le sommeil toutes les heures
- la perte de fatigue à la descente des TMR est visible immédiatement
## 12.0.49 - La deuxième lame d'Astrobazzarh
- Corrections
- les défenses particulières sont correctement affichées
- les vieux boucliers (sans catégorie de parade car créés il y a longtemps) peuvent parer...
- Les attaques à distance n'ont pas de difficulté libre
## 12.0.48 - La chèvre d'Astrobazzarh
- le Bandersnatch a une protection de 10
- la consistance chèvre est maintenant possible dans les recettes
alchimiques (et toutes les consistances avec accents)
@@ -45,10 +80,12 @@
- Correction: les réussites particulières fonctionnent avec les caractéristiques dérivées
## 12.0.47
- Correction sur les mise à jour en cascade -
- Correction sur le force rendering après un changement de competence
## 12.0.46 - Le double demi d'Astrobazzarh
- correction des raffraîchissement lors du sommeil qui empêchait de dormir
plusieurs heures
- Si la fatigue n'est pas utilisée, les rounds dans les TMR font perdre de l'endurance (au lieu d'en gagner)
@@ -75,18 +112,22 @@
- Correction des jets `@roll[vue/-2]` qui tentaient de chercher une compétence -2 (à cause des armes à 1/2 mains)
## 12.0.41 - La loupe d'Astrobazzarh
- On peut de nouveau effectuer des tirages cachés
- Le stress transformé est bien diminué lorsqu'on met le stress dans une compétence
## 12.0.40 - Les mains d'Astrobazzarh
- correction des attaques particulières en combat
- correction de message sur les min/max liés aux modificateurs de races (s'applique uniquement sur la taille)
## 12.0.39 - Les mains d'Astrobazzarh
- les armes à 1 ou 2 mains fonctionnent dans les liens de jets de dés
- commande `/jet` pour poster une demande de jet de dés
## 12.0.38 - Les prévisions d'Astrobazzarh
- Correction de modifications de personnages qui ne s'affichaient pas:
- changements d'endurance/vie/fatigue, transformé, ...
- Migration des compétences "Ecriture" en "Écriture" dans les tâches, livres, oeuvres et méditations
@@ -96,12 +137,14 @@
- utilisation de l'extension hbs pour tous les fichiers handlebars
## 12.0.37 - Les enchantements d'Astrobazzarh
- les potions ont un état, seules les potions liquides sont enchantables
- les lancements de sorts du jour sont conservés jusqu'à chateau dormant
- lorsqu'un joueur souhaite enchanter une potion, les sorts d'enchantements/purification/permanence doivent avoir été lancés auparavant
- on peut enchanter des gemmes exactement comme des potions
## 12.0.36 - L'alchimie d'Astrobazzarh
- Nouveautés
- ajout d'un bouton pour enchanter les potions
- standardisation des boutons d'actions sur les items
@@ -116,9 +159,11 @@
- Corrections de descriptions pour proposer les jet de dés
## 12.0.35 - La Solution d'Astrobazzarh
- Fix problème d'initialisation des feuilles d'items
## 12.0.34 - la tête d'Astrobazzarh
- support de liens "jets de dés"
- on peut ajouter des liens "jet de dés" dans les journaux, descriptions, notes, maladresses, ...
- avec la syntaxe `@roll[...]` on peut ajouter le lien vers:
@@ -133,28 +178,35 @@
- gestion des blocs secrets dans les descriptions
## 12.0.33 - la vieillesse d'Astrobazzarh
- retour de l'expérience pour les joueurs
- suppression du message "Pas de caractéristique" sur les jets d'odorat-goût
## 12.0.32 - les rêveries d'Astrobazzarh
- Ajout des Items Race pour gérer les ajustements liés aux races
## 12.0.31 - le mausolée d'Astrobazzarh
- Correction: les automatisation de combat jouer-MJ fonctionnentde nouveau
## 12.0.30 - le cauchemar d'Astrobazzarh
- calcul automatique du niveau des entités selon leur rêve
- la description des créatures venimeuses contient un lien vers leur venin
- Correction: les messages de combats ne marchaient plus (Changement combiné Foundry + rêve de Dragon)
## 12.0.29 - L'indexation d'Astrobazzarh
- les liens dans la descriptions des sorts pointent vers les sorts du compendium
- la description du chrasme contient le lien vers son venin plutôt qu'un tableau
## 12.0.28 - Les réserves d'Astrobazzarh
- possibilité de mettre en réserve depuis un sort connu
## 12.0.27 - Les vêtements d'Astrobazzarh
- Ajout de la liste des armures dans l'onglet caractéristiques
- Ajout d'une option pour choisir une carte des TMR alternatives
- Le Gardien peut créer des sorts en réserve parmi les sorts d'un personnage
@@ -175,12 +227,14 @@
- les modèles de personnages non joueurs sont non-liés par défaut
## 12.0.26 - Astrobazzarh le Haut-rêvant
- bouton pour le don de haut-rêve en un clic
- les compétences de draconic ne sont plus précédées de "Voie de"
- migration des compétences & compendiums
- Correction feuille simplifiée qui ne s'affichait pas en cas de sort variable
## 12.0.24 - Les ajustements d'Astrobazzarh
- amélioration
- meilleure gestion des noms des voies de draconic
- affichage du détail des sorts avec le nom de voie, 'court', la difficulté, le coût
@@ -190,6 +244,7 @@
- on peut maintenant saisir et supprimer les bonus de cases de manière intuitive
## 12.0.23 - La bibliothèque d'Astrobazzarh
- corrections mineures
- meilleure gestion de la parade des armes naturelles
- cas de "User lacks permission to update" pour les blessures et les StatusEffects
@@ -205,19 +260,23 @@
- dans les compendiums, les compétences Écriture et Épée ont une majuscule accentuée. Les Épée dans le compendium d'équipements référence le nom de compétence accentué.
## 12.0.21 - La nomination d'Astrobazzarh
- Les noms pour les messages dans le tchat sont maintenant ceux des tokens plutôt que ceux des acteurs
- Fix: le choix des effets dans les options s'affiche correctement
## 12.0.20 - Le tableau d'Astrobazzarh
- Ecran d'accueil officiel Scriptarium
## 12.0.19 - La témérité d'Astrobazzarh
- Fix
- les défenses des créatures sont correctement filtrées
- le lancer d'initiative pour tous les personnages/PNJs fonctionne correctement
- les lieux et commerces n'ont pas d'initiative
## 12.0.18 - A la barbe d'Astrobazzarh
- Améliorations sur la feuille de PNJ simplifiée
- Ajout du portrait
- Ajout du corps à corps
@@ -234,11 +293,13 @@
- Ajout d'un indicateur pour les armes de parade nécessitant une significative
## 12.0.16 - Le secret d'Astrobazzarh
- Fix: les jets envoyés messages uniquement au MJ ne sont plus envoyés à tous les autres joueurs (et dupliqués)
- Les noms affichés dans les automatisations de combat sont maintenant ceux des tokens plutôt que ceux des acteurs
- Ajout d'une option pour la localisation des blessures
## 12.0.15 - Le messager d'Astrobazzarh
- Correction des faces de dés personalisés dice-so-nice
- Les messages de maladies ne sont plus publics
- Les messages privés dans les TMR sont aussi envoyés au GM
@@ -246,6 +307,7 @@
- Amélioration du rendu des tables de compendiums (commande /table)
## 12.0.14 - Les légions d'Astrobazzarh
- Feuille de PNJ:
- boutons standard (encaissement, ...)
- boutons pour ajuster les compteurs
@@ -254,15 +316,18 @@
- gestion des armes
## 12.0.13 - La Chance d'Astrobazzarh
- Fix: jets de caractéristiques
## 12.0.12 - L'étalage d'Astrobazzarh
- Fix: On peut de nouveau vendre des items sans propriétaire, depuis les compendiums ou depuis l'onglet des Objets
- Début de Feuille PNJ au format des encarts Scriptarium
- support des jets de caractéristiques
- support des jets de compétences
## 12.0.11 - Le scriptorium d'Astrobazzarh
- ajout d'un bouton pour générer les éléments de description d'un personnage
- ajout du logo en background dans la liste des systèmes Foundry
- ajout d'un champ pour le métier
@@ -271,10 +336,12 @@
- export de l'esquive avec armure et sans armure
## 12.0.9 - 12.0.10 - Le scriptorium d'Astrobazzarh
- corrections de l'export scriptarium
- ajout d'une fonction avancée pour un exporter "scriptarium" des personnages
## 12.0.8 - La quincaillerie d'Astrobazzarh
- le propriétaire est indiqué dans les feuilles d'équipements/compétences/...
- Ecaille d'efficacité
- l'écaille d'efficacité est prise en compte même si on n'utilise pas le ciblage en combat
@@ -284,6 +351,7 @@
- le tooltip de l'initiative affiche correctement l'initiative
## 12.0.7 - La propriété d'Astrobazzarh
- correction des opérations faites à la création d'un Item:
- la durée des queues/rencontres/souffles
- les effets draconiques d'un souffle/queue
@@ -298,6 +366,7 @@
- la commande /voyage affiche maintenant les compétences liées au terrain
## 12.0.6 - Le bazar d'Astrobazzarh
- Corrections de l'inventaire en bazar:
- un problème pouvait survenir en déplaçant les objets
l'inventaire, qui fait qu'un conteneur se retrouve récursivement dans son
@@ -312,22 +381,26 @@
- Fix: restaurer la compatibilité Foundry 11
## 12.0.5 - Les mauvais jours d'Astrobazzarh
- Fix: on peut de nouveau ouvrir l'édition de calendrier
- Fix: on ne peut plus ouvrir plusieurs fenêtres de lancer de sort
- Fix: Failed to execute 'getComputedStyle' on 'Window'
## 12.0.4 - La plaie d'Astrobazzarh
- **Support V12**
- Fix: les boutons d'encaissement dans le tchat fonctionnent de nouveau
- Fix warnings sur "Die" et AudioHelper
## 12.0.3 - L'hémorragie d'Astrobazzarh
- **Support V12**
- On peut de nouveau ouvrir un acteur blessé après redémarrage du monde
- On peut de nouveau ouvrir les Items avec une rareté par environnement
- Le choix de ne plus afficher les demandes de suppression est bien pris en compte
## 12.0.2 - Les pluies d'Astrobazzarh
- **Support V12**
- correction des actions techniques déleguées au MJ qui bloquaient les fenêtre de lancer de dés des joueurs (et plein d'autres)
- la fenêtre de calendrier s'ouvre correctement
@@ -342,13 +415,16 @@
- correction d'erreurs intempestives 'User ... lacks permission to update ...'
# 11.2
## 11.2.21 - Le questionnement d'Akarlikarlikar
- Une confirmation spécifique est demandée pour monter dans les terres médianes en cas de rencontre en attente
- L'expérience en caractéristique sur les jets de chance et rêve actuels est mise dans la caractéristique correspondante
- Les effets s'appliquent correctement sur les créatures
- La date et l'heure (draconiques) sont affichées dans les messages du tchat
## 11.2.20 - Le soulagement d'Akarlikarlikar
- L'option "ajout de la difficulté d'attaque à l'encaissement" est affichée comme un modificateur d'encaissement
- Les options d'encaissement alternatives fonctionnent avec la validation de l'encaissement par le gardien
- La fenêtre d'astrologie du gardien affiche toutes les heures lues par un personnage
@@ -358,12 +434,15 @@
- Les messages de récupération de rêve en cas de Rêve de Dragon sont clarifiés
## 11.2.19 - Les hémorroïdes d'Akarlikarlikar
- La validation des jets d'encaissement par le Gardien fonctionne de nouveau
## 11.2.18 - Le bourrichon d'Akarlikarlikar
- Les différentes listes de la feuille de personnage ont maintenant le bouton pour envoyer dans le tchat
## 11.2.17 - Le cache-oeil d'Akarlikarlikar
- Le titre des fenêtre d'objet affiche de nouveau le type traduit
- Les tooltips des boutons edit/delete sont maintenant en Français
- La case à cocher "Cacher les points de tâches" fonctionne de nouveau
@@ -372,35 +451,43 @@
- La fenêtre des TMRs ne devrait plus afficher une zone noire au lieu de la carte.
## 11.2.16 - Le Tri d'Akarlikarlikar
- Tri alphabétique des items dans la fenêtre de création
- Mise à jour comptage de monde
## 11.2.15 - La Table d'Akarlikarlikar
- Tirage automatique de la foce d'une rencontre (via la commande /tmrr)
- Ajout de boutons pour ajouter des blessures "complètes" (ie avec perte d'endurance/vie)
## 11.2.14 - Les petits pas d'Akarlikarlikar
- Correction sur la gestion de la surprise
- Ordre des messages sur les cases humides
## 11.2.13 - Les cent pas d'Akarlikarlikar
- Ajout de la commande /voyage pour gérer la fatigue de marche des voyageurs
## 11.2.12 - Le somnifère d'Akarlikarlikar
- Fix: les potions enchantées n'empêchent plus de finir correctement Château Dormant
## 11.2.11 - Le miroir d'Akarlikarlikar
- Changement des images de compétence de créatures morsure/pinces pour être dans le thème
- Suppression de la bordure autour des portraits d'acteurs, remplacés par un légèr éclaircissement du fond
- Fix: le refoulement ajoute correctement un souffle et revient à 0 en cas d'échec
## 11.2.10 - Les expériences d'Akarlikarlikar
- En cas d'expérience des caractéristiques dérivées,
- si plusieurs caractéristiques pourraient recevoir l'expérience, une fenêtre demande au joueur
- si une seule caractéristique peut recevoir de l'expérience, c'est attribué automatiquement
- Si la force est au maximum pour la taille personnage, on ne peut plus gagner d'expérience
## 11.2.9 - La barbe d'Akarlikarlikar
- Amélioration des textes de tooltips
- Les tooltips sont plus dans le thème de couleur du système Rêve de Dragon
- Ajouts d'icones pour les attaque/initiative/soins dans les raccourcis sur les tokens (HUD)
@@ -412,19 +499,23 @@
- Changement de l'icône d'état d'empoignade pour suivre les couleurs des autres icônes d'état
## 11.2.8 - L'éclairage d'Akarlikarlikar
- l'ajustement de la lumière jour/nuit s'étale sur moins de temps (vaisseau et Lyre)
- les nouveaux tooltips ne masquent plus l'information d'expérience
- les jets de dés pour maîtriser les rencontres fonctionnent de nouveau
## 11.2.7 - Les explications d'Akarlikarlikar
- Ajout de tooltips sur la plupart des boutons, liens clickables, objets, tâches, ...
- Fix: on peut de nouveau regarder l'inventaire avec les droits limités/observateur
## 11.2.6 - Les réveils difficiles d'Akarlikarlikar
- Les changements de points de Cœur sont temporaires jusqu'à fin Château Dormant
- Fix: tous les petits fixes (feuille qui s'ouvre plus, compagnons animaux, potions qui bloquent Château Dormant, ...)
## 11.2.2 - Les tendres moments d'Akarlikarlikar
- On peut maintenant avoir des points de Cœur pour des suivants/compagnons
- diminuer les points de coeurs fait perdre du moral
- on peut proposer un tendre moment
@@ -443,11 +534,14 @@
ne bloquent plus les jets de dés
## v11.2.1 - La technique d'Akarlikarlikar
- On peut créer des armes pour Corps à corps et Esquive. Barreaux de chaise, armes improvisées, techniques d'art martiaux, pas de côté pour faire trébucher l'adversaire... A vous de voir comment imaginer de nouvelles "armes".
- Les armes avec une résistance de 0 ne peuvent pas être utilisées, une image et un rappel indiquent qu'elles sont cassées
Vu qu'elles ne peuvent pas être utilisées, permet de savoir pourquoi
## v11.2.0 - Les Terres médianes d'Akarlikarlikar
- Les TMRs sont redimensionables
- Nouveaux graphismes plus lisibles dans les TMRs
- Nouveau code couleur des icônes dans les TMR:
@@ -461,12 +555,15 @@ Vu qu'elles ne peuvent pas être utilisées, permet de savoir pourquoi
- Fix: Les jets d'encaissement forcés par le gardien à un résultat inférieur à 11 ne peuvent plus donner un deuxième d10 négatif
# v11.1
## v11.1.6 - Les dissections de Werther de Zloth
- Fix: on peut de nouveau donner des compétences aux créatures
- Fix: le délai de guérison d'une blessure rétrogradée est correctement appliqué
- Fix: l'encaissement à valider par le MJ fonctionne de nouveau
## v11.1.5 - Werther de Zloth l'Onirique
- Fixes:
- la demande de défense ne marchait plus
- la tête réserve extensible crée bien une case de réserve extensible (à modifier)
@@ -481,6 +578,7 @@ Vu qu'elles ne peuvent pas être utilisées, permet de savoir pourquoi
- pas de jets de vie pour les morts
## v11.1.4 - Werther de Zloth l'Onirique
- Ajout du facteur de significative à côté du pourcentage dans le résultat des jets de dés pour rappeler que le pourcentage n'est pas diviasé
- Fix: dans les TMRs, les tooltips affichent bien les informations de tous les effets sur la case
- Fix: la fatigue et l'éthylisme sont de nouveau pris en compte dans le calcul de l'éthylisme
@@ -490,15 +588,18 @@ Vu qu'elles ne peuvent pas être utilisées, permet de savoir pourquoi
- Esthétique: ne pas afficher "+0" pour les ajustements de jets/encaissement
## v11.1.2 - Les vertèbres de Werther de Zloth
- Fix: les jets d'encaissement fonctionnent de nouveau normalement
- Macro "Mon personnage" permettant au joueur d'accéder à sa feuille de personnage depuis la barre de macros
## v11.1.1 - Les fumebols de Werther de Zloth
- Fix: on peut de nouveau afficher les vues détaillées
- Fix: on peut ouvrir les sacs et contenants portés par les véhicules et créatures
- Fix: cuisiner du gibier prend maintenant bien les proportaions en compte
## v11.1.0 - Les choix de Werther de Zloth
- Les options suivantes peuvent être désactivées:
- La transformation de stress à Château Dormant
- La récuperation de chance à Château Dormant
@@ -516,7 +617,9 @@ Vu qu'elles ne peuvent pas être utilisées, permet de savoir pourquoi
- en cas de charge, les particulières sont toujours en force (p125)
# v11.0
## v11.0.28 - les fractures de Khrachtchoum
- La gravité de la blessure est affichée dans le résumé de l'encaissement
- Lors du changement d'acteur pendant le round
- le message annonçant le joueur dont c'est le tour ne contient plus d'informations de santé
@@ -528,12 +631,14 @@ Vu qu'elles ne peuvent pas être utilisées, permet de savoir pourquoi
- le moral est indiqué avant l'icone d'appel au moral
## v11.0.27 - Khrachtchoum le méticuleux
- le tooltip dans les TMR reste visible si on ne bouge pas la souris
- le surencombrement n'affecte QUE les actions physiques
- on peut de nouveau fabriquer une potion depuis la fenêtre d'édition de l'herbe
- si les TMR sont minimisées alors qu'une action est requise, elles sont bien réaffichées lorsque l'action est faite
## v11.0.26 - le crépuscule de Khrachtchoum
- gestion correcte des TMRs
- les TMRs ne sont jamais minimisées (par le système) quand le haut-rêvant est en demi-rêve
- lorsqu'une fenêtre liée aux demi-rêve est affichée, cliquer sur les TMRs n'a pas d'effet
@@ -552,45 +657,57 @@ Vu qu'elles ne peuvent pas être utilisées, permet de savoir pourquoi
- les jets de compétences d'attaque des créatures fonctionnent de nouveau
## v11.0.25 - la vision du rêve de Khrachtchoum
- Les TMRs restent affichées tant que le Haut-rêvant est en demi-rêve
## v11.0.24 - les couleurs de Khrachtchoum
- nouvelle carte des TMRs
## v11.0.23 - la lumière de Khrachtchoum
- ajustement automatique de la luminosité selon l'heure pour les scènes:
- avec une vision des tokens (sinon: ce n'est pas une scène de carte pour tokens)
- avec illumination globale (correspondant à une illumination extérieure)
- quand lampe "allumée" dans la fenêtre du calendrier
- avec une vision des tokens (sinon: ce n'est pas une scène de carte pour tokens)
- avec illumination globale (correspondant à une illumination extérieure)
- quand lampe "allumée" dans la fenêtre du calendrier
## v11.0.22 - les automatismes de Khrachtchoum le Problémeux
- Macro pour attaquer avec les compétences de créatures
## v11.0.20
- Macro pour attaquer avec les armes des personnages
## v11.0.17
- Fix: les actions de commerce ne s'appliquait pas bien aux personnages des tokens non liés
## v11.0.15 - L'apprentissage de Khrachtchoum
- Fix: l'expérience ne s'appliquait plus sur certaines réussites particulières (régression depuis la 11.0.7)
## v11.0.14 - Les pincettes de Khrachtchoum le Problémeux
- Correction du calcul de la place restante lors de l'ajout dans un conteneur
## v11.0.13 - La multiplication de l'eau de Khrachtchoum le Problémeux
- Correction de la vente depuis un commerce ayant des quantités illimitées
## v11.0.12 - Les poids de la mesure de Khrachtchoum le Problémeux
- Correction des malus de surencombrement
- Le malus armure est correctement affiché dans l'onglet des caractéristiques
- Correction d'orthographe et amélioration des messages des oeuvres d'art
## v11.0.11 - Les bleus de Khrachtchoum le Problémeux
- si le gardien configure le sommeil, les joueurs sont notifiés que chateau dormant vient de passer
- possibilité de créer des armes et des compétences de créatures non-mortelles.
## v11.0.10 - Les Songes de Khrachtchoum le Problémeux
- on peut de nouveau se déplacer dans les TMRs d'un clic sur la case à atteindre
- Lire un livre depuis l'inventaire permet de nouveau de faire un jet de la tâche
créée au lieu de créer toujours une nouvelle tâche
@@ -601,12 +718,14 @@ Vu qu'elles ne peuvent pas être utilisées, permet de savoir pourquoi
les heures dormies sont déduites des heures restant à dormir
## v11.0.9 - Les Souvenirs de Khrachtchoum le Problémeux
- mode de saisie de l'archétype en vue détaillée
- création une nouvelle incarnation depuis l'archétype
- réorganisation de la fenêtre de sélection des règles optionnelles
- correction de l'affichage du type dans les fenêtres d'objets
## v11.0.8 - la poigne de Sémolosse
- lien vers le changelog
- organisation des compendiums du système
- correction de l'empoignade

File diff suppressed because it is too large Load Diff

View File

@@ -12,14 +12,14 @@
/* =================== 3. some constants ============ */
--fieldset-background: url(/ui/parchment.jpg);
--rdd-color-text-primary: rgba(10, 10, 10, 0.9);
--rdd-input-background:rgba(0, 0, 0, 0.05);
--rdd-color-border-input: rgba(0, 0, 0, 0.2);
--rdd-bg-input: rgba(255, 255, 255, 0.1);
--color-controls:rgba(0, 0, 0, 0.9);
--rdd-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);
--color-controls:hsla(0, 0%, 0%, 0.9);
--color-controls-light:hsla(0, 0%, 20%, 0.8);
--color-controls-hover:hsla(60, 100%, 75%, 0.7);
--color-control-border-hover:rgba(255, 128, 0, 0.8);
--color-control-border-hover:hsla(30, 100%, 50%, 0.8);
--color-gold: rgba(191, 149, 63, 0.8);
--gradient-gold: linear-gradient(30deg, rgba(191, 149, 63, 0.3), rgba(252, 246, 186, 0.3), rgba(179, 135, 40, 0.3), rgba(251, 245, 183, 0.3), rgba(170, 119, 28, 0.3));
--gradient-silver: linear-gradient(30deg, rgba(61, 55, 93, 0.3), rgba(178, 179, 196, 0.3), rgba(59, 62, 63, 0.6), rgba(206, 204, 199, 0.3), rgba(61, 46, 49, 0.3));
@@ -39,12 +39,20 @@
hsla(50, 100%, 80%, 0.7)
);
--background-custom-button: linear-gradient(to bottom, rgba(33, 55, 74, 0.988) 5%, rgba(21, 40, 51, 0.671) 100%);
--background-custom-button-hover: linear-gradient(to bottom, rgb(128, 0, 0) 5%, rgb(62, 1, 1) 100%);
--background-custom-button: linear-gradient(to bottom, hsla(208, 38%, 21%, 0.988) 5%, hsla(202, 42%, 14%, 0.671) 100%);
--background-custom-button-hover: linear-gradient(to bottom, hsla(0, 100%, 25%, 1) 5%, hsla(0, 97%, 12%, 1) 100%);
--background-control-selected: linear-gradient(to bottom, hsla(0, 100%, 25%, 0.5) 5%, hsla(0, 100%, 12%, 0.5) 100%);
--background-tooltip: hsla(60, 12%, 85%, 0.95);
--background-tooltip-alt: hsla(60, 12%, 74%, 0.95);
--color-tooltip:hsla(282, 47%, 33%, 0.9);
--color-tooltip-faint:hsla(282, 47%, 66%, 0.5);
--background-error:hsla(16, 100%, 50%, 0.8);
--color-profile-border: hsla(0, 0%, 80%, 0.05);
--color-background-chat-message: hsla(60, 12%, 85%, 0.9);
--color-background-chat-whisper: repeating-linear-gradient(120deg,
hsla(60, 12%, 85%, 0.75),
hsla(60, 12%, 85%, 0.75) 1rem,
hsla(60, 12%, 85%, 0.8) 1rem,
hsla(60, 12%, 85%, 0.75) 1.5rem);
}

View File

@@ -59,6 +59,7 @@
}
/* Global styles & Font */
.application,
.window-app {
font-family: CaslonAntique;
text-align: justify;
@@ -80,5 +81,5 @@
.sheet header.sheet-header .header-compteurs,
.sheet header.sheet-header .flex-group-center.flex-fatigue,
select, .item-checkbox, #sidebar, #players, #navigation #nav-toggle {
font-family: "CaslonAntique"; /* For sheet parts; For nav and title */
font-family: "CaslonAntique"; /* For sheet parts; For nav and title */
}

View File

@@ -6,17 +6,14 @@
@import "item/monnaie.less";
@import "item/munition.less";
@import "item/tarot.less";
// body {
// --input-height: 1.4rem;
// }
@import "roll-dialog.less";
.window-header{
background: rgba(0,0,0,0.75);
}
.application .window-content,
.window-app.sheet .window-content {
margin: 0;
margin: 0.2rem;
padding: 0;
}
@@ -77,6 +74,17 @@
.sheet-header :is(.header-compteurs,.header-etats,.profile-img, .profile-img-token){
padding: 0 0.4rem;
}
.sheet-header div.header-etats {
width: calc(40% - 32px - 1rem);
height: 48px;
max-width: fit-content;
flex: initial;
flex-grow: 3;
div div{
display: flex;
flex-direction: row;
}
}
.sheet-header :is(.profile-img, .profile-img-token) {
-webkit-box-flex: 0;
@@ -115,13 +123,6 @@
max-width: fit-content;
}
.sheet-header div.header-etats {
width: calc(40% - 32px - 1rem);
height: 48px;
max-width: fit-content;
flex: initial;
}
.sheet-header .resource-content {
width: 2rem;
}
@@ -217,7 +218,6 @@
padding: 0;
}
.grid-competence-archetype {
display: grid;
grid-column: span 3 / span 3;
@@ -497,6 +497,7 @@
max-width: 1.5em;
max-height: 1.5em;
border-width: 0;
display: inline;
}
.dimmed {
opacity: 50%;
@@ -573,51 +574,55 @@
height: 100%;
}
.rdd.sheet .window-content {overflow: hidden;}
.rdd.sheet .window-content .sheet-body {overflow-y: scroll;}
.rdd.sheet .window-content .sheet-body .tab {padding-bottom: 30px;}
.rdd.sheet .window-content .sheet-body .competence-list {width: 100%;}
.rdd.sheet .window-content .sheet-body .carac-list {
width: 100%;
flex-grow: 0;
}
.rdd.sheet .window-content .sheet-body .carac-list .caracteristique {
flex-wrap: nowrap;
justify-content: stretch;
}
.rdd.sheet .window-content .sheet-body .carac-list .caracteristique.streched {
flex-wrap: nowrap;
justify-content: stretch;
flex-basis: 7.5em;
width: max-content;
}
.carac-label {
font-weight: bold;
flex-basis: 40%;
}
.rdd.sheet .window-content .sheet-body .carac-list .caracteristique > .utiliser-attribut {
flex-basis: available;
flex-grow: 1;
}
.rdd.sheet .window-content .sheet-body .carac-list .caracteristique .carac-value {
flex-basis: 15%;
flex-grow: 0;
}
.rdd.sheet .window-content .sheet-body .carac-list .caracteristique .carac-xp {
flex-basis: 13%;
flex-grow: 0;
}
.rdd.sheet .window-content .sheet-body .carac-list .caracteristique .derivee-label {
flex-grow: 1;
}
.rdd.sheet .window-content .sheet-body .carac-list .caracteristique .derivee-value {
flex-grow: 0;
flex-basis: 15%;
margin-right: 0.2rem;
margin-left: 0.2rem;
.rdd.sheet {
.window-content {
overflow: hidden;
.sheet-body {
overflow-y: scroll;
.tab {padding-bottom: 30px;}
.competence-list {width: 100%;}
.carac-list {
width: 100%;
flex-grow: 0;
.caracteristique.streched {
flex-wrap: nowrap;
justify-content: stretch;
flex-basis: 7.5em;
width: max-content;
}
.caracteristique {
flex-wrap: nowrap;
justify-content: stretch;
.carac-value {
flex-basis: 15%;
flex-grow: 0;
}
.carac-xp {
flex-basis: 13%;
flex-grow: 0;
}
.derivee-label {
flex-grow: 1;
}
.derivee-value {
flex-grow: 0;
flex-basis: 15%;
margin-right: 0.2rem;
margin-left: 0.2rem;
}
}
}
}
}
}
.flex-grow-1 {
flex-grow: 1;
}
@@ -641,6 +646,7 @@
font-size: 1rem;
letter-spacing: 1px;
}
.app.sheet div.form-group {
clear: both;
display: flex;
@@ -808,6 +814,7 @@
font-size: 0.8rem;
text-align: right;
}
.placeholder-ajustements {
flex-direction: column;
}
@@ -820,32 +827,31 @@
background-color: lightblue;
}
div.placeholder-resolution span.table-proba-reussite{
span.table-proba-reussite{
font-size: 0.8rem;
padding: 5px;
}
.poesie-extrait {
max-height: 8rem;
font-size: 0.8rem;
font-style: italic;
color: rgba(82, 17, 131, 0.9);
overflow: hidden;
}
.poesie-reference{
.poesie-extrait:hover {
max-height: unset;
overflow: visible;
opacity: 1;
}
.poesie-reference {
font-size: 0.7rem;
text-align: right;
}
.poesie-overflow {
color: rgba(82, 17, 131, 0.9);
max-height: 1.5rem;
overflow: hidden;
border-left: 1px dotted black; /* If you want dots under the hoverable text */
}
.poesie-overflow:hover {
max-height: unset;
overflow: visible;
border-left: 0px
}
.type-compendium{
.type-compendium {
font-size: 0.6rem;
}
@@ -914,27 +920,26 @@
color: var(--color-text-dark-primary);
border-radius: 3px;
}
.app-calendar-astrologie div.theme-astral{
width: 14rem;
margin: 0.4rem;
}
.app-calendar-astrologie div.horloge-roue {
position: relative;
left: calc(50% - 6.5rem);
width: 13rem;
height: 13rem;
}
.app-calendar-astrologie div.horloge-roue div.horloge-heure {
position: absolute;
width: 1.8rem;
height: 1.8rem;
}
.app-calendar-astrologie div.horloge-roue div.horloge-heure img.horloge-heure-img {
width: 2rem;
height: 2rem;
.app-calendar-astrologie{
div.theme-astral{
width: 14rem;
margin: 0.4rem;
}
div.horloge-roue {
position: relative;
left: calc(50% - 6.5rem);
width: 13rem;
height: 13rem;
div.horloge-heure {
position: absolute;
width: 1.8rem;
height: 1.8rem;
img.horloge-heure-img {
width: 2rem;
height: 2rem;
}
}
}
}
.window-app .window-content, .window-app.sheet .window-content .sheet-body{
@@ -1017,7 +1022,7 @@
max-width: 90%;
}
.window-app.sheet .window-content .tooltip:hover .tooltiptext {
.window-app.sheet .window-content :is(.tooltip, .tooltip-overflow):hover .tooltiptext {
top: 2rem;
left: 2rem;
margin: 0;
@@ -1468,27 +1473,29 @@
cursor: pointer;
}
.chat-message h4 {
font-size: 0.9rem;
.chat-message {
background: var(--color-background-chat-message);
h4 {
font-size: 0.9rem;
}
.message-content {
text-align: justify;
}
header.message-header .heure-rdd {
font-size: 0.7rem;
flex-grow: 3;
}
hr {
margin: 0.2rem 0;
}
}
.chat-message .message-content {
text-align: justify;
}
.chat-message header.message-header .heure-rdd {
font-size: 0.7rem;
flex-grow: 3;
}
.chat-message.whisper {
background: rgba(220,220,210,0.75);
background: var(--color-background-chat-whisper);
border: 2px solid #545469;
}
.chat-message hr {
margin: 0.2rem 0;
}
.chat-icon {
border: 0;
padding: 2px 6px 2px 2px;
@@ -1504,49 +1511,57 @@
vertical-align: text-top;
}
#sidebar-tabs {
flex: 0 0 28px;
box-sizing: border-box;
margin: 0 0 3px;
border-bottom: 1px solid rgba(0,0,0,0);
box-shadow: inset 0 0 2rem rgba(0,0,0,0.5);
.actor-img-small {
max-width: 1.5rem;
max-height: 1.5rem;
flex-grow: 0;
margin-right: 0.2rem;
vertical-align: bottom;
}
#sidebar-tabs > .item.active {
border: 1px solid rgba(114,98,72,1);
background: rgba(30, 25, 20, 0.75);
box-shadow: 0 0 6px inset rgba(114,98,72,1);
#sidebar-tabs menu {
button:is(
[data-tab="chat"],
[data-tab="combat"],
[data-tab="scenes"],
[data-tab="actors"],
[data-tab="items"],
[data-tab="journal"],
[data-tab="cards"],
[data-tab="macros"],
[data-tab="tables"],
[data-tab="playlists"],
[data-tab="compendium"],
[data-tab="settings"]
)::before{ content: none; }
button {
background-repeat: no-repeat;
}
button[aria-pressed="false"] {
background-color: hsla(30, 37%, 50%, 0.5);
}
button[aria-pressed="true"] {
border: 1px solid hsla(15, 80%, 30%, 1);
background-color: hsla(30, 100%, 90%, 0.6);
box-shadow: 0 0 3px inset hsla(15, 80%, 30%, 1);
}
button[data-tab="chat"] { background-image: url("../assets/ui/icon_sidebar_chat.svg"); }
button[data-tab="combat"] { background-image: url("../assets/ui/icon_sidebar_fight.svg"); }
button[data-tab="scenes"] { background-image: url("../assets/ui/icon_sidebar_scene.svg"); }
button[data-tab="actors"] { background-image: url("../assets/ui/icon_sidebar_actor.svg"); }
button[data-tab="items"] { background-image: url("../assets/ui/icon_sidebar_item.svg"); }
button[data-tab="journal"] { background-image: url("../assets/ui/icon_sidebar_journal.svg"); }
button[data-tab="cards"] { background-image: url("../assets/ui/icon_sidebar_cards.svg"); }
button[data-tab="macros"] { background-image: url("../assets/ui/icon_sidebar_macros.svg"); }
button[data-tab="tables"] { background-image: url("../assets/ui/d100.svg"); }
button[data-tab="playlists"] { background-image: url("../assets/ui/icon_sidebar_music.svg"); }
button[data-tab="compendium"] { background-image: url("../assets/ui/icon_sidebar_compendium.svg"); }
button[data-tab="settings"] { background-image: url("../assets/ui/icon_sidebar_settings.svg"); }
}
#sidebar #sidebar-tabs i{
width: 23px;
height: 23px;
display: inline-block;
background-position:center;
background-size:cover;
text-shadow: 1px 1px 0 rgba(0,0,0,0.75);
}
#sidebar #sidebar-tabs i:is(
.fa-comments, .fa-fist-raised, .fa-swords,
.fa-users, .fa-user, .fa-map, .fa-suitcase,
.fa-book-open, .fa-th-list, .fa-music,
.fa-atlas,.fa-cogs
):before {content: "";}
#sidebar #sidebar-tabs i.fa-comments {background: url("../assets/ui/icon_sidebar_chat.svg") no-repeat;}
#sidebar #sidebar-tabs i.fa-fist-raised {background: url("../assets/ui/icon_sidebar_fight.svg") no-repeat;}
#sidebar #sidebar-tabs i.fa-swords {background: url("../assets/ui/icon_sidebar_fight.svg") no-repeat;}
#sidebar #sidebar-tabs i.fa-user {background: url("../assets/ui/icon_sidebar_actor.svg") no-repeat;}
#sidebar #sidebar-tabs i.fa-users {background: url("../assets/ui/icon_sidebar_actor.svg") no-repeat;}
#sidebar #sidebar-tabs i.fa-map {background: url("../assets/ui/icon_sidebar_scene.svg") no-repeat;}
#sidebar #sidebar-tabs i.fa-suitcase {background: url("../assets/ui/icon_sidebar_item.svg") no-repeat;}
#sidebar #sidebar-tabs i.fa-book-open {background: url("../assets/ui/icon_sidebar_journal.svg") no-repeat;}
#sidebar #sidebar-tabs i.fa-th-list {background: url("../assets/ui/icon_sidebar_rolltable.svg") no-repeat;}
#sidebar #sidebar-tabs i.fa-music {background: url("../assets/ui/icon_sidebar_music.svg") no-repeat;}
#sidebar #sidebar-tabs i.fa-atlas {background: url("../assets/ui/icon_sidebar_compendium.svg") no-repeat;}
#sidebar #sidebar-tabs i.fa-cogs {background: url("../assets/ui/icon_sidebar_settings.svg") no-repeat;}
// #sidebar #sidebar-tabs i.fa-th-list {background: url("../assets/ui/icon_sidebar_rolltable.svg") no-repeat;}
#combat #combat-controls {
box-shadow: inset 0 0 2rem rgba(0,0,0,0.5);
}
@@ -1631,63 +1646,6 @@
border-image-outset: 0px;
}
.window-app.calendar {
display: inline-block;
background: none;
margin: 0;
padding: 0;
box-shadow: none;
pointer-events: none;
max-height: fit-content;
}
.window-app.calendar header.window-header {
min-width: fit-content;
height: 1.4rem;
pointer-events: all;
}
.window-app.calendar .window-content {
margin: 0;
padding: 0;
z-index: 100;
flex-direction: column;
min-width: 250px;
height: fit-content;
background: hsla(0, 0%, 0%, 0.0);
font-family: "GoudyAcc";
pointer-events: none;
}
.window-app.calendar .window-content div:is(.calendar-boutons-heure, .horloge-digitale) {
pointer-events: all;
}
.window-app.calendar .window-content div.horloge-analogique {
pointer-events: none;
}
.window-app.calendar .window-content div.horloge-analogique div.horloge-roue {
pointer-events: all;
}
.window-app.calendar div.horloge-roue {
position: relative;
margin-bottom: 7px;
left: 0;
width: 8rem;
height: 8rem;
}
.window-app.calendar div.horloge-roue div.horloge-heure {
width: 1.4rem;
height: 1.4rem;
}
.window-app.calendar div.horloge-roue div.horloge-heure img.horloge-heure-img {
width: 1.4rem;
height: 1.4rem;
}
div.horloge-roue div {
position: absolute;
border: none;
@@ -1732,74 +1690,130 @@
div.horloge-roue div img {
border: none;
}
.calendar {
display: inline-block;
background: none;
margin: 0;
padding: 0;
box-shadow: none;
pointer-events: none;
max-height: fit-content;
header.window-header {
min-width: fit-content;
height: 1.4rem;
pointer-events: all;
h4 {
font-size: 0.8rem;
}
}
.window-content {
margin: 0;
padding: 0;
z-index: 100;
flex-direction: column;
min-width: 250px;
height: fit-content;
background: hsla(0, 0%, 0%, 0.0);
font-family: "GoudyAcc";
pointer-events: none;
div.calendar-boutons-heure {
display: grid;
background: hsla(0, 0%, 20%, 1);
color: hsla(0, 0%, 80%, 0.8);
pointer-events: all;
}
div.horloge-digitale {
pointer-events: all;
}
div.horloge-analogique {
pointer-events: none;
}
div.horloge-analogique div.horloge-roue {
pointer-events: all;
}
}
div.horloge-roue {
position: relative;
margin-bottom: 7px;
left: 0;
width: 8rem;
height: 8rem;
div.horloge-heure {
width: 1.4rem;
height: 1.4rem;
img.horloge-heure-img {
width: 1.4rem;
height: 1.4rem;
}
}
}
.window-app.calendar div.horloge-heure.heure-01 { top: calc(50% - 0.7rem + sin(-180deg) *38%); left: calc(50% - 0.7rem + cos(-180deg) *38%); }
.window-app.calendar div.horloge-heure.heure-02 { top: calc(50% - 0.7rem + sin(-150deg) *38%); left: calc(50% - 0.7rem + cos(-150deg) *38%); }
.window-app.calendar div.horloge-heure.heure-03 { top: calc(50% - 0.7rem + sin(-120deg) *38%); left: calc(50% - 0.7rem + cos(-120deg) *38%); }
.window-app.calendar div.horloge-heure.heure-04 { top: calc(50% - 0.7rem + sin(-90deg) *38%); left: calc(50% - 0.7rem + cos(-90deg) *38%); }
.window-app.calendar div.horloge-heure.heure-05 { top: calc(50% - 0.7rem + sin(-60deg) *38%); left: calc(50% - 0.7rem + cos(-60deg) *38%); }
.window-app.calendar div.horloge-heure.heure-06 { top: calc(50% - 0.7rem + sin(-30deg) *38%); left: calc(50% - 0.7rem + cos(-30deg) *38%); }
.window-app.calendar div.horloge-heure.heure-07 { top: calc(50% - 0.7rem + sin(-0deg) *38%); left: calc(50% - 0.7rem + cos(-0deg) *38%); }
.window-app.calendar div.horloge-heure.heure-08 { top: calc(50% - 0.7rem + sin(30deg) *38%); left: calc(50% - 0.7rem + cos(30deg) *38%); }
.window-app.calendar div.horloge-heure.heure-09 { top: calc(50% - 0.7rem + sin(60deg) *38%); left: calc(50% - 0.7rem + cos(60deg) *38%); }
.window-app.calendar div.horloge-heure.heure-10 { top: calc(50% - 0.7rem + sin(90deg) *38%); left: calc(50% - 0.7rem + cos(90deg) *38%); }
.window-app.calendar div.horloge-heure.heure-11 { top: calc(50% - 0.7rem + sin(120deg) *38%); left: calc(50% - 0.7rem + cos(120deg) *38%); }
.window-app.calendar div.horloge-heure.heure-12 { top: calc(50% - 0.7rem + sin(150deg) *38%); left: calc(50% - 0.7rem + cos(150deg) *41%); }
.window-app.calendar-astrologie div.horloge-heure.heure-01 { top: calc(50% - 1rem + sin(-180deg) *41%); left: calc(50% - 1rem + cos(-180deg) *41%); }
.window-app.calendar-astrologie div.horloge-heure.heure-02 { top: calc(50% - 1rem + sin(-150deg) *41%); left: calc(50% - 1rem + cos(-150deg) *41%); }
.window-app.calendar-astrologie div.horloge-heure.heure-03 { top: calc(50% - 1rem + sin(-120deg) *41%); left: calc(50% - 1rem + cos(-120deg) *41%); }
.window-app.calendar-astrologie div.horloge-heure.heure-04 { top: calc(50% - 1rem + sin(-90deg) *41%); left: calc(50% - 1rem + cos(-90deg) *41%); }
.window-app.calendar-astrologie div.horloge-heure.heure-05 { top: calc(50% - 1rem + sin(-60deg) *41%); left: calc(50% - 1rem + cos(-60deg) *41%); }
.window-app.calendar-astrologie div.horloge-heure.heure-06 { top: calc(50% - 1rem + sin(-30deg) *41%); left: calc(50% - 1rem + cos(-30deg) *41%); }
.window-app.calendar-astrologie div.horloge-heure.heure-07 { top: calc(50% - 1rem + sin(-0deg) *41%); left: calc(50% - 1rem + cos(-0deg) *41%); }
.window-app.calendar-astrologie div.horloge-heure.heure-08 { top: calc(50% - 1rem + sin(30deg) *41%); left: calc(50% - 1rem + cos(30deg) *41%); }
.window-app.calendar-astrologie div.horloge-heure.heure-09 { top: calc(50% - 1rem + sin(60deg) *41%); left: calc(50% - 1rem + cos(60deg) *41%); }
.window-app.calendar-astrologie div.horloge-heure.heure-10 { top: calc(50% - 1rem + sin(90deg) *41%); left: calc(50% - 1rem + cos(90deg) *41%); }
.window-app.calendar-astrologie div.horloge-heure.heure-11 { top: calc(50% - 1rem + sin(120deg) *41%); left: calc(50% - 1rem + cos(120deg) *41%); }
.window-app.calendar-astrologie div.horloge-heure.heure-12 { top: calc(50% - 1rem + sin(150deg) *41%); left: calc(50% - 1rem + cos(150deg) *41%); }
.window-app.calendar-astrologie div.horloge-ajustement.heure-01 { top: calc(50% - 0.4rem + sin(180deg) * 28%); left: calc(50% - 0.4rem + cos(180deg) * 28%); }
.window-app.calendar-astrologie div.horloge-ajustement.heure-02 { top: calc(50% - 0.4rem + sin(-150deg) * 28%); left: calc(50% - 0.4rem + cos(-150deg) * 28%); }
.window-app.calendar-astrologie div.horloge-ajustement.heure-03 { top: calc(50% - 0.4rem + sin(-120deg) * 28%); left: calc(50% - 0.4rem + cos(-120deg) * 28%); }
.window-app.calendar-astrologie div.horloge-ajustement.heure-04 { top: calc(50% - 0.4rem + sin(-90deg) * 28%); left: calc(50% - 0.4rem + cos(-90deg) * 28%); }
.window-app.calendar-astrologie div.horloge-ajustement.heure-05 { top: calc(50% - 0.4rem + sin(-60deg) * 28%); left: calc(50% - 0.4rem + cos(-60deg) * 28%); }
.window-app.calendar-astrologie div.horloge-ajustement.heure-06 { top: calc(50% - 0.4rem + sin(-30deg) * 28%); left: calc(50% - 0.4rem + cos(-30deg) * 28%); }
.window-app.calendar-astrologie div.horloge-ajustement.heure-07 { top: calc(50% - 0.4rem + sin(0deg) * 28%); left: calc(50% - 0.4rem + cos(0deg) * 28%); }
.window-app.calendar-astrologie div.horloge-ajustement.heure-08 { top: calc(50% - 0.4rem + sin(30deg) * 28%); left: calc(50% - 0.4rem + cos(30deg) * 28%); }
.window-app.calendar-astrologie div.horloge-ajustement.heure-09 { top: calc(50% - 0.4rem + sin(60deg) * 28%); left: calc(50% - 0.4rem + cos(60deg) * 28%); }
.window-app.calendar-astrologie div.horloge-ajustement.heure-10 { top: calc(50% - 0.4rem + sin(90deg) * 28%); left: calc(50% - 0.4rem + cos(90deg) * 28%); }
.window-app.calendar-astrologie div.horloge-ajustement.heure-11 { top: calc(50% - 0.4rem + sin(120deg) * 28%); left: calc(50% - 0.4rem + cos(120deg) * 28%); }
.window-app.calendar-astrologie div.horloge-ajustement.heure-12 { top: calc(50% - 0.4rem + sin(150deg) * 28%); left: calc(50% - 0.4rem + cos(150deg) * 28%); }
.window-app.calendar header.window-header h4 {
font-size: 0.8rem;
div.horloge-heure.heure-01 { top: calc(50% - 0.7rem + sin(-180deg) *38%); left: calc(50% - 0.7rem + cos(-180deg) *38%); }
div.horloge-heure.heure-02 { top: calc(50% - 0.7rem + sin(-150deg) *38%); left: calc(50% - 0.7rem + cos(-150deg) *38%); }
div.horloge-heure.heure-03 { top: calc(50% - 0.7rem + sin(-120deg) *38%); left: calc(50% - 0.7rem + cos(-120deg) *38%); }
div.horloge-heure.heure-04 { top: calc(50% - 0.7rem + sin(-90deg) *38%); left: calc(50% - 0.7rem + cos(-90deg) *38%); }
div.horloge-heure.heure-05 { top: calc(50% - 0.7rem + sin(-60deg) *38%); left: calc(50% - 0.7rem + cos(-60deg) *38%); }
div.horloge-heure.heure-06 { top: calc(50% - 0.7rem + sin(-30deg) *38%); left: calc(50% - 0.7rem + cos(-30deg) *38%); }
div.horloge-heure.heure-07 { top: calc(50% - 0.7rem + sin(-0deg) *38%); left: calc(50% - 0.7rem + cos(-0deg) *38%); }
div.horloge-heure.heure-08 { top: calc(50% - 0.7rem + sin(30deg) *38%); left: calc(50% - 0.7rem + cos(30deg) *38%); }
div.horloge-heure.heure-09 { top: calc(50% - 0.7rem + sin(60deg) *38%); left: calc(50% - 0.7rem + cos(60deg) *38%); }
div.horloge-heure.heure-10 { top: calc(50% - 0.7rem + sin(90deg) *38%); left: calc(50% - 0.7rem + cos(90deg) *38%); }
div.horloge-heure.heure-11 { top: calc(50% - 0.7rem + sin(120deg) *38%); left: calc(50% - 0.7rem + cos(120deg) *38%); }
div.horloge-heure.heure-12 { top: calc(50% - 0.7rem + sin(150deg) *38%); left: calc(50% - 0.7rem + cos(150deg) *41%); }
}
.window-app.calendar section.window-content div.calendar-boutons-heure {
display: grid;
background: hsla(0, 0%, 20%, 1);
color: hsla(0, 0%, 80%, 0.8);
.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);
border: none;
vertical-align: bottom;
max-width: 1.2em;
max-height: 1.2em;
margin: 1px;
}
i {
border: 1px solid rgba(0, 0, 0, 0);
}
a:hover {
color: var(--color-controls-hover);
border: 1px solid var(--color-control-border-hover);
cursor: pointer;
}
}
.calendar-boutons-heure .calendar-btn:is(.calendar-lyre,.calendar-vaisseau) img {
color: hsla(0, 0%, 100%, 0.5);
border: none;
vertical-align: bottom;
max-width: 1.2em;
max-height: 1.2em;
margin: 1px;
}
.calendar-boutons-heure i {
border: 1px solid rgba(0, 0, 0, 0);
}
.calendar-boutons-heure a:hover {
color: var(--color-controls-hover);
border: 1px solid var(--color-control-border-hover);
cursor: pointer;
}
.calendar-1min { grid-column: 1/1; }
.calendar-5min { grid-column: 2/2; }
@@ -1827,21 +1841,19 @@
background: hsla(0, 0%, 20%, 1);
text-align: center;
width: 100%;
}
div.horloge-digitale :is(.calendar-heure-texte,.calendar-minute-texte) {
font-size: 1rem;
pointer-events: all;
margin: 0;
}
div.horloge-digitale a {
border: 1px solid rgba(0, 0, 0, 0);
}
div.horloge-digitale a:hover {
color: var(--color-controls-hover);
border: 1px solid var(--color-control-border-hover);
cursor: pointer;
:is(.calendar-heure-texte,.calendar-minute-texte) {
font-size: 1rem;
pointer-events: all;
margin: 0;
}
a {
border: 1px solid rgba(0, 0, 0, 0);
}
a:hover {
color: var(--color-controls-hover);
border: 1px solid var(--color-control-border-hover);
cursor: pointer;
}
}
div.calendar-timestamp-edit select.calendar-signe-heure {
@@ -1853,66 +1865,78 @@
position: relative;
display: inline-block;
}
.tooltip-overflow {
display: inline-block;
}
.tooltip-dotted {
border-bottom: 1px dotted black; /* If you want dots under the hoverable text */
}
/* Tooltip text */
.tooltip .tooltiptext {
text-align: center;
/* Position the tooltip text */
div.message-content span .tooltip-overflow {
overflow: visible;
position: absolute;
z-index: 1;
/* Fade in tooltip */
visibility: hidden;
opacity: 0;
transition: opacity 0.3s;
span {
overflow: visible;
position: relative;
}
}
.tooltip .left-competence {
transform: translate(-100%, 0%);
/* Show the tooltip text when you mouse over the tooltip container */
:is(.tooltip, .tooltip-overflow):hover {
.tooltiptext {
visibility: visible;
opacity: 1;
}
}
/* html Tooltips html*/
:is(.tooltip, .tooltip-overflow){
.tooltiptext {
text-align: center;
/* Position the tooltip text */
position: absolute;
z-index: 1;
/* Fade in tooltip */
visibility: hidden;
opacity: 0;
transition: opacity 0.3s;
}
.tooltip .ttt-fatigue{
width: 360px;
.ttt-fatigue {
width: 360px;
background: rgba(30, 25, 20, 0.9);
border-image: url(../assets/ui/bg_control.webp) 21 repeat;
border-image-slice: 6 6 6 6 fill;
border-image-width: 6px 6px 6px 6px;
border-image-outset: 0px 0px 0px 0px;
border-radius: 0px;
background: rgba(30, 25, 20, 0.9);
border-image: url(../assets/ui/bg_control.webp) 21 repeat;
border-image-slice: 6 6 6 6 fill;
border-image-width: 6px 6px 6px 6px;
border-image-outset: 0px 0px 0px 0px;
border-radius: 0px;
font-size: 0.8rem;
padding: 3px 0;
}
font-size: 0.8rem;
padding: 3px 0;
}
.tooltip .ttt-ajustements {
width: 150px;
background: var(--background-tooltip);
border-radius: 6px;
font-size: 0.9rem;
padding: 3px 0;
}
.tooltip .ttt-titre {
text-align: justify;
width: 100%;
top: 30px;
background: var(--background-tooltip);
border-radius: 6px;
font-size: 0.9rem;
padding: 3px;
.ttt-ajustements {
width: 10rem;
background: var(--background-tooltip);
border-radius: 6px;
font-size: 0.9rem;
padding: 3px 0;
div:nth-child(odd) {
background: var(--background-tooltip-alt);
}
}
}
aside#tooltip {
max-width: 15rem;
background: var(--background-tooltip);
/*color: var(--color-text-dark-primary);*/
color: rgba(100, 100, 50, 0.85);
font-size: 1rem;
font-size: 0.9rem;
border-radius: 0.2rem;
padding: 0.4rem;
padding: 0.3rem;
font-family: "CaslonAntique";
}
aside#tooltip span.reference {
@@ -1924,19 +1948,6 @@
color: var(--color-tooltip-faint);
}
.tooltip :is(.ttt-xp,.ttt-levelup) {
width: 250px;
background: var(--background-tooltip) !important;
border-radius: 6px;
font-size: 0.9rem;
padding: 3px 0;
}
/* Show the tooltip text when you mouse over the tooltip container */
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}
.chat-card-button, .chat-card-button-pushed {
border-radius: 0.2rem;

220
less/roll-dialog.less Normal file
View File

@@ -0,0 +1,220 @@
.roll-dialog {
font-family: CaslonAntique;
display: grid;
grid-template-areas:
"header header header header header header header"
"action action action action action action action"
"mode separation separation separation separation separation separation"
"mode carac carac carac comp comp resume"
"mode choix choix choix choix choix modifiers"
"mode resolution resolution resolution resolution resolution modifiers"
"mode chances chances chances chances chances buttons"
"footer footer footer footer footer footer footer";
grid-template-columns: 2rem 1rem 1fr 1fr 2fr 2fr 3fr;
gap: 0.2rem;
roll-header { grid-area: header; }
roll-line { grid-area: separation; }
roll-action { grid-area: action; }
roll-carac { grid-area: carac; }
roll-comp { grid-area: comp; }
roll-choix { grid-area: choix; }
roll-table { grid-area: resolution; }
roll-conditions { grid-area: modifiers; }
roll-chances { grid-area: chances; }
roll-resume { grid-area: resume; }
roll-buttons { grid-area: buttons; }
roll-mode {
grid-area: mode;
display: flex;
flex-direction: column;
}
roll-conditions roll-section[name="rollmode"],
roll-mode {
button[data-checked="true"] {
background-color: var(--color-text-selection-bg);
color: var(--color-controls);
i { filter: invert(0.8); }
img { filter: invert(0.2); }
}
button {
height: 1.8rem;
width: 1.8rem;
gap: 0.5rem;
padding: 0.2rem;
background-color: var(--button-background-color);
color: var(--color-controls);
i { filter: invert(0.2); }
img { filter: invert(0.8); }
}
}
:is(roll-carac, roll-comp) {
display: flex;
flex-direction: row;
align-items: baseline;
}
roll-section,
roll-section div {
display: flex;
flex-direction: row;
align-items: anchor-center;
margin: 0 0.2rem;
}
roll-resume {
display: flex;
flex-direction: row;
img.button-effect-img {
filter: invert(0.8);
}
}
roll-choix roll-section {
display: grid;
grid-template-areas:
"selection selection"
"img roll-part";
grid-template-columns: 3.2rem 1fr;
gap: 0.2rem;
align-items: start;
subline {
grid-area: selection;
display: flex;
flex-direction: row;
}
roll-part-img {
display: flex;
flex-direction: column;
grid-area: img;
img{
border: 0;
padding: 1px;
max-height: 3rem;
max-width: 3rem;
object-fit: contain;
height: 100%;
}
}
roll-part-detail {
grid-area: roll-part;
display: flex;
flex-direction: column;
align-items: normal;
subline {
display: flex;
flex-direction: row;
div.poesie-extrait{
display: flex;
flex-direction: column;
}
}
}
}
roll-section selected-numeric-value {
display: flow;
width: 2.5rem;
text-align: right;
margin: 0 0.2rem 0 0.5rem;
padding: 0 0.2rem;
}
roll-action {
flex-basis: content;
display: flex;
flex-direction: row;
align-items: center;
border-bottom: 0.2rem solid;
font-size: 1.2rem;
font-weight: bold;
roll-section {
display: flex;
flex-direction: row;
align-items: center;
img.action-img {
float: left;
}
img {
max-width: 3rem;
max-height: 3rem;
margin: 0 1rem;
padding: 0;
}
}
}
roll-conditions {
display: flex;
flex-direction: column;
}
:is(roll-action, roll-carac, roll-comp) roll-section {
flex-basis: content;
}
:is(roll-choix, roll-conditions, roll-carac, roll-comp) {
select {
max-height: 1.6rem;
margin: 0 0.2rem;
padding: 0 0.2rem;
}
input[type="number"] {
max-height: 1.6rem;
max-width: 2.5rem;
margin: 0 0.2rem;
padding: 0 0.2rem;
}
img {
max-width: 1.8rem;
max-height: 1.8rem;
margin: 0 0.2rem;
padding: 0;
}
}
roll-carac select[name="select-carac"] {
max-width: 6rem;
}
roll-comp select[name="select-comp"] {
min-width: 8rem;
max-width: 11rem;
margin-left: 1rem;
}
roll-conditions roll-section[name="coeur"] select[name="coeur"] {
max-width: 4rem;
}
roll-conditions roll-section[name="tricher"] img {
/* image de d100 */
max-width: 2.5rem;
max-height: 2.5rem;
gap: 0;
margin: 0;
padding: 0;
filter: invert(0.8);
}
roll-buttons {
display: flex;
flex-direction: row-reverse;
}
roll-table {
table tr :is(th, td) {
padding: 0.1rem;
width: 1.5rem;
text-align: center;
}
}
}

View File

@@ -1,7 +1,5 @@
import { RdDUtility } from "./rdd-utility.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDItemArme } from "./item-arme.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDBonus } from "./rdd-bonus.js";
import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js";
@@ -9,11 +7,12 @@ import { RdDCarac } from "./rdd-carac.js";
import { DialogSplitItem } from "./dialog-split-item.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { STATUSES } from "./settings/status-effects.js";
import { MAINS_DIRECTRICES } from "./actor.js";
import { RdDBaseActorReveSheet } from "./actor/base-actor-reve-sheet.js";
import { ITEM_TYPES } from "./constants.js";
import { RdDItem } from "./item.js";
import { RdDItemArme } from "./item/arme.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemBlessure } from "./item/blessure.js";
import { RdDEmpoignade } from "./rdd-empoignade.js";
import { RdDBaseActorSangSheet } from "./actor/base-actor-sang-sheet.js";
@@ -34,7 +33,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
width: 550,
showCompNiveauBase: false,
vueArchetype: false,
}, { inplace: false });
}, { inplace: false })
}
/* -------------------------------------------- */
@@ -78,14 +77,10 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
});
// toujours avoir une liste d'armes (pour mettre esquive et corps à corps)
const actor = this.actor;
formData.combat = foundry.utils.duplicate(formData.armes);
RdDItemArme.computeNiveauArmes(formData.combat, formData.competences);
formData.combat.push(RdDItemArme.corpsACorps(actor));
formData.combat.push(RdDItemArme.empoignade(actor));
const actor = this.actor
formData.esquives = this.actor.getCompetencesEsquive()
formData.combat = RdDCombatManager.listActionsArmes(formData.combat, formData.competences, formData.system.carac);
formData.combat = actor.listActionsAttaque()
formData.empoignades = this.actor.getEmpoignades();
this.armesList = formData.combat;
@@ -95,7 +90,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
formData.difficultesLibres = CONFIG.RDD.difficultesLibres;
formData.hautreve = {
isDemiReve: this.actor.getEffect(STATUSES.StatusDemiReve),
isDemiReve: this.actor.isDemiReve(),
cacheTMR: this.actor.isTMRCache()
}
@@ -217,13 +212,17 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
this.html.find('.roll-reve-actuel').click(async event => await this.actor.rollCarac('reve-actuel', { resistance: true }))
this.html.find('.action-empoignade').click(async event => await RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor)))
this.html.find('.roll-arme').click(async event => await this.actor.rollArme(foundry.utils.duplicate(this._getEventArmeCombat(event)), 'competence'))
this.html.find('.roll-arme').click(async event => {
const action = this._getActionCombat(event);
await this.actor.rollArme(action.arme, action.main)
})
// Initiative pour l'arme
this.html.find('.roll-init-arme').click(async event => {
let combatant = game.combat.combatants.find(c => c.actor.id == this.actor.id)
if (combatant) {
RdDCombatManager.rollInitiativeAction(combatant._id, this._getEventArmeCombat(event));
RdDCombatManager.rollInitiativeAction(combatant._id, this._getActionCombat(event));
} else {
ui.notifications.info("Impossible de lancer l'initiative sans être dans un combat.");
}
@@ -237,11 +236,11 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
this.html.find('.carac-xp-augmenter').click(async event => await this.actor.updateCaracXPAuto(event.currentTarget.name.replace("augmenter.", "")))
this.html.find('.competence-xp-augmenter').click(async event => await this.actor.updateCompetenceXPAuto(RdDSheetUtility.getItemId(event)))
this.html.find('.competence-stress-augmenter').click(async event =>{
this.html.find('.competence-stress-augmenter').click(async event => {
await this.actor.updateCompetenceStress(RdDSheetUtility.getItemId(event))
this.render(true)
}
)
}
)
if (this.options.vueDetaillee) {
// On carac change
@@ -347,13 +346,17 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
await this.actor.createItem('tache', 'Nouvelle tache');
}
_getEventArmeCombat(event) {
_getActionCombat(event) {
const li = this.html.find(event.currentTarget)?.parents(".item");
let armeName = li.data("arme-name");
let compName = li.data('competence-name');
const arme = this.armesList.find(a => a.name == armeName && a.system.competence == compName);
const arme = this.armesList.find(a => a.arme.name == armeName && a.comp.name == compName);
if (!arme) {
return { name: armeName, system: { competence: compName } };
return {
name: armeName,
arme: { name: armeName },
comp: { name: compName }
}
}
return arme;
}

40
module/actor-token.mjs Normal file
View File

@@ -0,0 +1,40 @@
/**
* class providing the actor and token, and choosing the name and image from the token if available.
*/
export class ActorToken {
static fromActorId(actorId, onError = () => undefined) {
actorId = actorId ?? (canvas.tokens.controlled.length > 0
? canvas.tokens.controlled[0].actor.id
: undefined)
const actor = actorId ? game.actors.get(actorId) : undefined
if (actor) {
return this.fromActor(actor)
}
return onError()
}
static fromActor(actor) {
const token = actor.isToken ? actor.token : actor.prototypeToken
return ActorToken.fromToken(token)
}
static fromTokenId(tokenId, sceneId = undefined) {
const tokensList = sceneId ? game.scenes.get(sceneId).tokens : canvas.tokens.placeables
const token = tokensList.get(tokenId)
return ActorToken.fromToken(token)
}
static fromToken(token) {
return new ActorToken(token)
}
constructor(token) {
this.name = token.name ?? token.actor.name
this.img = token.texture.src ?? token.actor.img
this.actor = token.actor
this.id = token.actor?.id
this.token = token
this.tokenId = token?.id
}
}

View File

@@ -8,12 +8,9 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDDice } from "./rdd-dice.js";
import { RdDRollTables } from "./rdd-rolltables.js";
import { ChatUtility } from "./chat-utility.js";
import { RdDItemSort } from "./item-sort.js";
import { Grammar } from "./grammar.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDAlchimie } from "./rdd-alchimie.js";
import { STATUSES } from "./settings/status-effects.js";
import { RdDItemSigneDraconique } from "./item/signedraconique.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
import { Draconique } from "./tmr/draconique.js";
@@ -22,13 +19,11 @@ import { DialogConsommer } from "./dialog-item-consommer.js";
import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js";
import { RollDataAjustements } from "./rolldata-ajustements.js";
import { RdDPossession } from "./rdd-possession.js";
import { SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { ACTOR_TYPES, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { RdDConfirm } from "./rdd-confirm.js";
import { RdDRencontre } from "./item/rencontre.js";
import { DialogRepos } from "./sommeil/dialog-repos.js";
import { RdDBaseActor } from "./actor/base-actor.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDItemBlessure } from "./item/blessure.js";
import { AppAstrologie } from "./sommeil/app-astrologie.js";
import { RdDEmpoignade } from "./rdd-empoignade.js";
import { ExperienceLog, XP_TOPIC } from "./actor/experience-log.js";
@@ -36,13 +31,23 @@ import { ITEM_TYPES } from "./constants.js";
import { RdDBaseActorSang } from "./actor/base-actor-sang.js";
import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { DialogChoixXpCarac } from "./dialog-choix-xp-carac.js";
import { RdDItemArme } from "./item-arme.js";
import { RdDCombatManager } from "./rdd-combat.js";
import { RdDItemArme } from "./item/arme.js";
import { RdDItemBlessure } from "./item/blessure.js";
import { RdDItemTete } from "./item/tete.js";
import { RdDItemSort } from "./item-sort.js";
import { RdDItemRace } from "./item/race.js";
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 { RdDItemRace } from "./item/race.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 } from "./settings/options-avancees.js";
export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre']
@@ -105,7 +110,7 @@ export class RdDActor extends RdDBaseActorSang {
return Number.isNumeric(this.system.compteurs.chance.value) ?
Misc.toInt(this.system.compteurs.chance.value) : this.getChance()
}
getMoralTotal() { return this.system.compteurs.moral?.value ?? 0 }
getMoralTotal() { return parseInt(this.system.compteurs.moral?.value ?? 0) }
getEnduranceMax() { return Math.max(1, Math.max(this.getTaille() + this.getConstitution(), this.getVieMax() + this.getVolonte())) }
@@ -113,8 +118,10 @@ export class RdDActor extends RdDBaseActorSang {
getEtatGeneral(options = { ethylisme: false }) {
const etatGeneral = this.system.compteurs.etat?.value ?? 0
// Pour les jets d'Ethylisme, on retire le malus d'éthylisme (p.162)
const annuleMalusEthylisme = options.ethylisme ? this.malusEthylisme() : 0
return etatGeneral - annuleMalusEthylisme
if (options.ethylisme) {
return etatGeneral - this.malusEthylisme()
}
return etatGeneral
}
/* -------------------------------------------- */
@@ -129,19 +136,13 @@ export class RdDActor extends RdDBaseActorSang {
.reduce(Misc.sum(), 0);
}
listActionsCombat() {
listActions({ isAttaque = false, isEquipe = false }) {
// Recupération des armes
const actions = RdDCombatManager.listActionsArmes(
this.itemTypes[ITEM_TYPES.arme]
.filter(it => RdDItemArme.isAttaque(it))
.concat(RdDItemArme.corpsACorps(this))
.concat(RdDItemArme.empoignade(this))
,
this.itemTypes[ITEM_TYPES.competence],
this.system.carac)
const actions = this.listActionsAttaque()
.filter(it => !isEquipe || it.arme.system.equipe)
if (this.system.attributs.hautrevant.value) {
actions.push({ name: "Draconic", action: 'haut-reve', system: { initOnly: true, competence: "Draconic" } });
if (!isAttaque && this.system.attributs.hautrevant.value) {
actions.push({ name: "Draconic", action: 'haut-reve', initOnly: true })
}
return actions
}
@@ -166,6 +167,86 @@ export class RdDActor extends RdDBaseActorSang {
.find(it => true)
}
/* -------------------------------------------- */
/** Retourne une liste triée d'actions d'armes avec le split arme1 main / arme 2 main / lancer */
listActionsAttaque() {
let actions = [
this.$prepareAttaqueArme(RdDItemArme.empoignade(this)),
this.$prepareAttaqueArme(RdDItemArme.corpsACorps(this)),
]
const armes = this.itemTypes[ITEM_TYPES.arme]
.filter(it => RdDItemArme.isAttaque(it))
.sort(Misc.ascending(it => it.name));
for (const arme of armes) {
if (arme.system.unemain && arme.system.competence) {
actions.push(this.$prepareAttaqueArme(arme, '(1 main)'))
}
if (arme.system.deuxmains && arme.system.competence) {
actions.push(this.$prepareAttaqueArme(arme, '(2 mains)'))
}
if (arme.system.lancer) {
actions.push(this.$prepareAttaqueArme(arme, '(lancer)'))
}
if (arme.system.tir) {
actions.push(this.$prepareAttaqueArme(arme, '(tir)'))
}
}
return actions;
}
/* -------------------------------------------- */
$prepareAttaqueArme(arme, main) {
const comp = this.getCompetence(RdDActor.$getCompetenceAction(arme, main))
const caracCode = RdDActor.$getCaracAction(comp, main)
const caracValue = this.system.carac[caracCode].value
const dommages = arme.system.dommages.toString()
// TODO: déplacer sur RdDItemArme
if (arme.system.unemain && arme.system.deuxmains && !dommages.includes("/")) {
ui.notifications.info(`Les dommages de l'arme à 1/2 mains ${arme.name} ne sont pas corrects (ie sous la forme X/Y)`)
}
const tableauDommages = dommages.includes("/") ? dommages.split("/") : [dommages, dommages]
const dmg = main == '(2 mains)' ? tableauDommages[1] : tableauDommages[0]
const niveau = comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(main) ? -8 : -6)
const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + (arme.system.magique) ? arme.system.ecaille_efficacite : 0
return {
name: arme.name + (main ? ' ' + main : ''),
action: 'attaque',
initOnly: false,
arme: arme,
comp: comp,
main: main,
carac: { key: caracCode, value: caracValue },
equipe: arme.system.equipe,
dmg: dmg,
initiative: RdDInitiative.calculInitiative(niveau, caracValue, ajustement)
}
}
static $getCaracAction(comp, main) {
if (comp?.system.defaut_carac) {
return comp.system.defaut_carac
}
switch (main) {
case '(lancer)': return 'lancer'
case '(tir)': return 'tir'
default: return 'melee'
}
}
static $getCompetenceAction(arme, main) {
switch (main) {
case '(1 main)': return arme.competence1Mains()
case '(2 mains)': return arme.competence2Mains()
case '(lancer)': return arme.system.lancer
case '(tir)': return arme.system.tir
default: return arme.system.competence
}
}
/* -------------------------------------------- */
async $perteReveEnchantementsChateauDormants() {
const toUpdate = this.items.filter(it => [ITEM_TYPES.potion, ITEM_TYPES.gemme].includes(it.type))
@@ -673,7 +754,7 @@ export class RdDActor extends RdDBaseActorSang {
if (to > Misc.toInt(this.system.reve.seuil.value)) {
updates[`system.reve.seuil.value`] = to; // SFA : Direct and packed changes
//this.setPointsDeSeuil(to);
}
}
}
if (caracName == LIST_CARAC_PERSONNAGE.chance.code) {
if (to > Misc.toInt(this.system.compteurs.chance.value)) {
@@ -895,8 +976,14 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
ethylisme() {
return this.system.compteurs.ethylisme?.value ?? 1;
}
malusEthylisme() {
return Math.min(0, (this.system.compteurs.ethylisme?.value ?? 0));
return Math.min(0, this.ethylisme())
}
isAlcoolise() {
return this.ethylisme() < 1
}
@@ -1482,7 +1569,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
createCallbackAppelAuMoral() { /* Si l'appel au moral est utilisé, on l'affiche dans le chat et on diminue éventuellement le moral */
return {
action: r => this._appliquerAppelMoral(r)
action: r => this.appliquerAppelMoral(r)
};
}
@@ -1578,12 +1665,12 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
async _appliquerAppelMoral(rollData) {
async appliquerAppelMoral(rollData) {
if (!rollData.use.moral || game.settings.get("core", "rollMode") == 'selfroll') {
return
}
if (rollData.rolled.isEchec ||
(rollData.ajustements.diviseurSignificative && (rollData.rolled.roll * rollData.ajustements.diviseurSignificative > rollData.score))) {
(rollData.diviseurSignificative && (rollData.rolled.roll * rollData.diviseurSignificative > rollData.rolled.score))) {
rollData.perteMoralEchec = rollData.moral <= -3 ? 'dissolution' : 'perte';
rollData.moral = await this.moralIncDec(-1); /* L'appel au moral a échoué. Le personnage perd un point de moral */
}
@@ -1591,20 +1678,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
$filterSortList(sortList, coord) {
let tmr = TMRUtility.getTMR(coord);
let filtered = []
for (let sort of sortList) {
if (sort.system.caseTMR.toLowerCase().includes('variable')) {
filtered.push(sort);
} else if (sort.system.caseTMRspeciale.toLowerCase().includes('variable')) {
filtered.push(sort);
} else if (sort.system.caseTMR.toLowerCase() == tmr.type) {
filtered.push(sort);
} else if (sort.system.caseTMR.toLowerCase().includes('special') && sort.system.caseTMRspeciale.toLowerCase().includes(coord.toLowerCase())) {
filtered.push(sort);
}
}
return filtered;
return sortList.filter(it => RdDItemSort.isSortOnCoord(it, coord))
}
/* -------------------------------------------- */
@@ -1630,8 +1704,8 @@ export class RdDActor extends RdDBaseActorSang {
ui.notifications.error("Une queue ou un souffle vous empèche de lancer de sort!")
return
}
// Duplication car les pts de reve sont modifiés dans le sort
let sorts = foundry.utils.duplicate(this.$filterSortList(this.itemTypes['sort'], coord));
// Duplication car les pts de reve sont modifiés dans le sort!
let sorts = foundry.utils.duplicate(this.itemTypes[ITEM_TYPES.sort].filter(it => RdDItemSort.isSortOnCoord(it, coord)))
if (sorts.length == 0) {
ui.notifications.info(`Aucun sort disponible en ${TMRUtility.getTMR(coord).label} !`);
return;
@@ -1919,153 +1993,6 @@ export class RdDActor extends RdDBaseActorSang {
}
}
/* -------------------------------------------- */
async _rollArt(artData, selected, oeuvre, callbackAction = async r => await this._resultArt(r)) {
oeuvre.system.niveau = oeuvre.system.niveau ?? 0;
foundry.utils.mergeObject(artData,
{
oeuvre: oeuvre,
art: oeuvre.type,
competence: foundry.utils.duplicate(this.getCompetence(artData.compName ?? oeuvre.system.competence ?? artData.art)),
diffLibre: - oeuvre.system.niveau,
diffConditions: 0,
use: { libre: false, conditions: true, surenc: false },
selectedCarac: foundry.utils.duplicate(this.system.carac[selected])
},
{ overwrite: false });
artData.competence.system.defaut_carac = selected;
if (!artData.forceCarac) {
artData.forceCarac = {};
artData.forceCarac[selected] = foundry.utils.duplicate(this.system.carac[selected]);
}
await this.openRollDialog({
name: `jet-${artData.art}`,
label: `${artData.verbe} ${oeuvre.name}`,
template: `systems/foundryvtt-reve-de-dragon/templates/dialog-roll-${oeuvre.type}.hbs`,
rollData: artData,
callbacks: [{ action: callbackAction }],
})
}
/* -------------------------------------------- */
async _resultArt(artData) {
const niveau = artData.oeuvre.system.niveau ?? 0;
const baseQualite = (artData.rolled.isSuccess ? niveau : artData.competence.system.niveau);
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite;
await RdDRollResult.displayRollData(artData, this.name, `chat-resultat-${artData.art}.hbs`);
}
/* -------------------------------------------- */
async rollChant(id) {
const artData = { art: 'chant', verbe: 'Chanter' };
const oeuvre = foundry.utils.duplicate(this.getChant(id));
await this._rollArt(artData, "ouie", oeuvre);
}
/* -------------------------------------------- */
async rollDanse(id) {
const artData = { art: 'danse', verbe: 'Danser', forceCarac: {} };
const oeuvre = foundry.utils.duplicate(this.findItemLike(id, artData.art));
if (oeuvre.system.agilite) {
artData.forceCarac['agilite'] = foundry.utils.duplicate(this.system.carac.agilite);
}
if (oeuvre.system.apparence) {
artData.forceCarac['apparence'] = foundry.utils.duplicate(this.system.carac.apparence);
}
const selectedCarac = this._getCaracDanse(oeuvre);
await this._rollArt(artData, selectedCarac, oeuvre);
}
/* -------------------------------------------- */
_getCaracDanse(oeuvre) {
if (oeuvre.system.agilite) { return "agilite"; }
else if (oeuvre.system.apparence) { return "apparence"; }
const compData = this.getCompetence(oeuvre.system.competence);
return compData.system.defaut_carac;
}
/* -------------------------------------------- */
async rollMusique(id) {
const artData = { art: 'musique', verbe: 'Jouer' };
const oeuvre = this.findItemLike(id, artData.art);
await this._rollArt(artData, "ouie", oeuvre);
}
/* -------------------------------------------- */
async rollRecetteCuisine(id) {
const oeuvre = this.getRecetteCuisine(id);
const artData = {
verbe: 'Cuisiner',
compName: 'cuisine',
proportions: 1,
ajouterEquipement: false
};
await this._rollArt(artData, 'odoratgout', oeuvre, r => this._resultRecetteCuisine(r));
}
/* -------------------------------------------- */
async _resultRecetteCuisine(cuisine) {
const niveauRecette = cuisine.oeuvre.system.niveau ?? 0;
const baseQualite = (cuisine.rolled.isSuccess ? niveauRecette : cuisine.competence.system.niveau);
cuisine.qualiteFinale = Math.min(baseQualite, niveauRecette) + cuisine.rolled.ptQualite;
cuisine.exotismeFinal = Math.min(Math.min(cuisine.qualiteFinale, cuisine.oeuvre.system.exotisme ?? 0), 0);
cuisine.sust = cuisine.oeuvre.system.sust * Math.min(cuisine.proportions, cuisine.proportionsMax ?? cuisine.proportions)
const platCuisine = {
name: cuisine.oeuvre.name,
type: 'nourritureboisson',
img: 'systems/foundryvtt-reve-de-dragon/icons/objets/provision_cuite.webp',
system: {
"description": cuisine.oeuvre.system.description,
"sust": 1,
"qualite": cuisine.qualiteFinale,
"exotisme": cuisine.exotismeFinal,
"encombrement": 0.1,
"quantite": Math.max(1, Math.floor(cuisine.sust)),
"cout": Math.max(cuisine.qualiteFinale) * 0.01
}
}
if (cuisine.ajouterEquipement) {
await this.createEmbeddedDocuments('Item', [platCuisine]);
ui.notifications.info(`${platCuisine.system.quantite} rations de ${platCuisine.name} ont été ajoutés à votre équipement`);
}
cuisine.platCuisine = platCuisine;
await RdDRollResult.displayRollData(cuisine, this.name, `chat-resultat-${cuisine.art}.hbs`);
}
async preparerNourriture(item) {
if (item.getUtilisationCuisine() == 'brut') {
const nourriture = {
name: 'Plat de ' + item.name,
type: 'recettecuisine',
img: item.img,
system: {
sust: item.system.sust,
exotisme: item.system.exotisme,
ingredients: item.name
}
};
const artData = {
verbe: 'Préparer',
compName: 'cuisine',
proportions: 1,
proportionsMax: Math.min(50, item.system.quantite),
ajouterEquipement: true
};
await this._rollArt(artData, 'odoratgout', nourriture, async (cuisine) => {
await this._resultRecetteCuisine(cuisine);
const remaining = Math.max(item.system.quantite - cuisine.proportions, 0);
if (remaining > 0) {
await item.update({ 'system.quantite': remaining })
}
else {
await this.deleteEmbeddedDocuments('Item', [item.id]);
}
});
}
}
/* -------------------------------------------- */
async rollJeu(id) {
const oeuvre = this.getJeu(id);
@@ -2081,14 +2008,9 @@ export class RdDActor extends RdDBaseActorSang {
listCarac.forEach(c => artData.forceCarac[c] = this.system.carac[c]);
artData.competence.system.niveauReel = artData.competence.system.niveau;
artData.competence.system.niveau = Math.max(artData.competence.system.niveau, oeuvre.system.base);
await this._rollArt(artData, carac, oeuvre);
await this._rollArtV1(artData, carac, oeuvre);
}
async rollOeuvre(id) {
const artData = { art: 'oeuvre', verbe: 'Interpréter' }
const oeuvre = foundry.utils.duplicate(this.findItemLike(id, artData.art))
await this._rollArt(artData, oeuvre.system.default_carac, oeuvre)
}
/* -------------------------------------------- */
async rollMeditation(id) {
@@ -2122,7 +2044,7 @@ export class RdDActor extends RdDBaseActorSang {
if (meditationRoll.rolled.isSuccess) {
await this.createEmbeddedDocuments("Item", [RdDItemSigneDraconique.prepareSigneDraconiqueMeditation(meditationRoll.meditation, meditationRoll.rolled)]);
}
if (meditationRoll.rolled.isEPart){
if (meditationRoll.rolled.isEPart) {
await this.updateEmbeddedDocuments('Item', [{ _id: meditationRoll.meditation._id, 'system.malus': meditationRoll.meditation.system.malus - 1 }]);
}
await this.santeIncDec("fatigue", 2);
@@ -2432,7 +2354,7 @@ export class RdDActor extends RdDBaseActorSang {
this.tmrApp.forceTMRDisplay()
return
}
if (mode != 'visu' && this.getEffect(STATUSES.StatusDemiReve)) {
if (mode != 'visu' && this.isDemiReve()) {
ui.notifications.warn("Les personnage est déjà dans les Terres Médianes, elles s'affichent en visualisation")
mode = "visu"; // bascule le mode en visu automatiquement
}
@@ -2712,8 +2634,11 @@ export class RdDActor extends RdDBaseActorSang {
listeSuivants(filter = suivant => true) {
return RdDActor.$buildSubActorLinks(
this.system.subacteurs.suivants.filter(filter), RdDActor.$transformSubActeurSuivant
)
this.system.subacteurs.suivants, RdDActor.$transformSubActeurSuivant
).filter(filter)
}
listeAmoureux() {
return this.listeSuivants(it => it.coeur > 0 && it.type == ACTOR_TYPES.personnage)
}
getSuivant(subActorId) {
@@ -3123,5 +3048,204 @@ export class RdDActor extends RdDBaseActorSang {
await incarnation.remiseANeuf();
incarnation.sheet.render(true);
}
/* -------------------------------------------- */
async _rollArtV2(oeuvreId, callbackAction = async (actor, rd) => await actor._resultArtV2(rd)) {
const oeuvre = this.items.get(oeuvreId)
const rollData = {
title: `Interpretation de ${oeuvre.name} par ${this.name}`,
mode: {
allowed: ["oeuvre"]
},
selected: {
mode: "oeuvre",
oeuvre: { key: oeuvre.id },
},
ids: {
actorId: this.id
}
}
await RollDialog.create(rollData, {
onRoll: (dialog) => {
this._onCloseRollDialog(),
dialog.close()
},
customChatMessage: true,
callbacks: [callbackAction]
})
}
async _resultArtV2(artData) {
const niveau = artData.oeuvre.system.niveau ?? 0;
const baseQualite = (artData.rolled.isSuccess ? niveau : artData.competence.system.niveau);
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite;
await RdDRollResult.displayRollData(artData, this.name, `chat-resultat-${artData.art}.hbs`);
}
/* -------------------------------------------- */
async rollOeuvre(id) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
return await this._rollArtV2(id)
}
else {
const artData = { art: 'oeuvre', verbe: 'Interpréter' }
const oeuvre = foundry.utils.duplicate(this.findItemLike(id, artData.art))
await this._rollArtV1(artData, oeuvre.system.default_carac, oeuvre)
}
}
async rollChant(id) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
await this._rollArtV2(id)
}
else {
const artData = { art: 'chant', verbe: 'Chanter' }
const oeuvre = foundry.utils.duplicate(this.getChant(id))
await this._rollArtV1(artData, "ouie", oeuvre)
}
}
async rollDanse(id) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
await this._rollArtV2(id)
}
else {
const artData = { art: 'danse', verbe: 'Danser', forceCarac: {} }
const oeuvre = foundry.utils.duplicate(this.findItemLike(id, artData.art))
let selectedCarac = this.getCompetence(oeuvre.system.competence)?.system.defaut_carac
if (oeuvre.system.apparence) {
artData.forceCarac['apparence'] = foundry.utils.duplicate(this.system.carac.apparence)
selectedCarac = "apparence"
}
if (oeuvre.system.agilite) {
artData.forceCarac['agilite'] = foundry.utils.duplicate(this.system.carac.agilite)
selectedCarac = "agilite"
}
await this._rollArtV1(artData, selectedCarac, oeuvre)
}
}
async rollMusique(id) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
await this._rollArtV2(id)
}
else {
const artData = { art: 'musique', verbe: 'Jouer' }
const oeuvre = this.findItemLike(id, artData.art)
await this._rollArtV1(artData, "ouie", oeuvre)
}
}
/* -------------------------------------------- */
async _rollArtV1(artData, selected, oeuvre, callbackAction = async r => await this._resultArt(r)) {
oeuvre.system.niveau = oeuvre.system.niveau ?? 0;
foundry.utils.mergeObject(artData,
{
oeuvre: oeuvre,
art: oeuvre.type,
competence: foundry.utils.duplicate(this.getCompetence(artData.compName ?? oeuvre.system.competence ?? artData.art)),
diffLibre: - oeuvre.system.niveau,
diffConditions: 0,
use: { libre: false, conditions: true, surenc: false },
selectedCarac: foundry.utils.duplicate(this.system.carac[selected])
},
{ overwrite: false });
artData.competence.system.defaut_carac = selected;
if (!artData.forceCarac) {
artData.forceCarac = {};
artData.forceCarac[selected] = foundry.utils.duplicate(this.system.carac[selected]);
}
await this.openRollDialog({
name: `jet-${artData.art}`,
label: `${artData.verbe} ${oeuvre.name}`,
template: `systems/foundryvtt-reve-de-dragon/templates/dialog-roll-${oeuvre.type}.hbs`,
rollData: artData,
callbacks: [{ action: callbackAction }],
})
}
async _resultArt(artData) {
const niveau = artData.oeuvre.system.niveau ?? 0;
const baseQualite = (artData.rolled.isSuccess ? niveau : artData.competence.system.niveau);
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite;
await RdDRollResult.displayRollData(artData, this.name, `chat-resultat-${artData.art}.hbs`);
}
/* -------------------------------------------- */
async rollRecetteCuisine(id) {
const oeuvre = this.getRecetteCuisine(id);
const artData = {
verbe: 'Cuisiner',
compName: 'cuisine',
proportions: 1,
ajouterEquipement: false
};
await this._rollArtV1(artData, 'odoratgout', oeuvre, r => this._resultRecetteCuisine(r));
}
/* -------------------------------------------- */
async _resultRecetteCuisine(cuisine) {
const niveauRecette = cuisine.oeuvre.system.niveau ?? 0;
const baseQualite = (cuisine.rolled.isSuccess ? niveauRecette : cuisine.competence.system.niveau);
cuisine.qualiteFinale = Math.min(baseQualite, niveauRecette) + cuisine.rolled.ptQualite;
cuisine.exotismeFinal = Math.min(Math.min(cuisine.qualiteFinale, cuisine.oeuvre.system.exotisme ?? 0), 0);
cuisine.sust = cuisine.oeuvre.system.sust * Math.min(cuisine.proportions, cuisine.proportionsMax ?? cuisine.proportions)
const platCuisine = {
name: cuisine.oeuvre.name,
type: 'nourritureboisson',
img: 'systems/foundryvtt-reve-de-dragon/icons/objets/provision_cuite.webp',
system: {
"description": cuisine.oeuvre.system.description,
"sust": 1,
"qualite": cuisine.qualiteFinale,
"exotisme": cuisine.exotismeFinal,
"encombrement": 0.1,
"quantite": Math.max(1, Math.floor(cuisine.sust)),
"cout": Math.max(cuisine.qualiteFinale) * 0.01
}
}
if (cuisine.ajouterEquipement) {
await this.createEmbeddedDocuments('Item', [platCuisine]);
ui.notifications.info(`${platCuisine.system.quantite} rations de ${platCuisine.name} ont été ajoutés à votre équipement`);
}
cuisine.platCuisine = platCuisine;
await RdDRollResult.displayRollData(cuisine, this.name, `chat-resultat-${cuisine.art}.hbs`);
}
async preparerNourriture(item) {
if (item.getUtilisationCuisine() == 'brut') {
const nourriture = {
name: 'Plat de ' + item.name,
type: 'recettecuisine',
img: item.img,
system: {
sust: item.system.sust,
exotisme: item.system.exotisme,
ingredients: item.name
}
};
const artData = {
verbe: 'Préparer',
compName: 'cuisine',
proportions: 1,
proportionsMax: Math.min(50, item.system.quantite),
ajouterEquipement: true
};
await this._rollArtV1(artData, 'odoratgout', nourriture, async (cuisine) => {
await this._resultRecetteCuisine(cuisine);
const remaining = Math.max(item.system.quantite - cuisine.proportions, 0);
if (remaining > 0) {
await item.update({ 'system.quantite': remaining })
}
else {
await this.deleteEmbeddedDocuments('Item', [item.id]);
}
});
}
}
}

View File

@@ -8,15 +8,16 @@ import { RdDUtility } from "../rdd-utility.js";
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
import { RdDBaseActor } from "./base-actor.js";
import { ITEM_TYPES } from "../constants.js";
import { RdDItemCompetence } from "../item-competence.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
import { RdDItemArme } from "../item-arme.js";
import { StatusEffects } from "../settings/status-effects.js";
import { StatusEffects, STATUSES } from "../settings/status-effects.js";
import { Targets } from "../targets.js";
import { RdDConfirm } from "../rdd-confirm.js";
import { RdDCarac } from "../rdd-carac.js";
import { RdDRollResult } from "../rdd-roll-result.js";
import { RdDItemCompetence } from "../item-competence.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
import { RdDItemArme } from "../item/arme.js";
import { ChatUtility } from "../chat-utility.js";
import { DialogValidationEncaissement } from "../dialog-validation-encaissement.js";
import { RdDCombat } from "../rdd-combat.js";
@@ -79,6 +80,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
getBonusDegat() { return RdDCarac.getCaracDerivee(this.getEncombrementMax()).plusdom }
getMoralTotal() { return 0 }
listeAmoureux() {return []}
getProtectionNaturelle() { return Number(this.system.attributs?.protection?.value ?? 0) }
getSConst() { return 0 }
@@ -108,10 +110,11 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
return this.system.carac[competence.system.defaut_carac].value;
}
listActionsCombat() {
listActions({ isAttaque = false, isEquipe = false }) {
return this.itemTypes[ITEM_TYPES.competencecreature]
.filter(it => RdDItemCompetenceCreature.isAttaque(it))
.map(it => RdDItemCompetenceCreature.armeCreature(it))
.map(it => RdDItemCompetenceCreature.attaqueCreature(it))
.filter(it => it != undefined);
}
@@ -164,11 +167,16 @@ export class RdDBaseActorReve extends RdDBaseActor {
if (idOrName instanceof Item) {
return idOrName.isCompetence() ? idOrName : undefined
}
return RdDItemCompetence.findCompetence(this.items, idOrName, options)
return RdDItemCompetence.findCompetence(
this.items.filter(it => [ITEM_TYPES.competence, ITEM_TYPES.competencecreature].includes(it.type)),
idOrName, options)
}
getCompetences(name, options = { onMessage: message => { } }) {
return RdDItemCompetence.findCompetences(this.items, name, options)
getCompetences(name = undefined, options = { onMessage: message => { } }) {
if (name == undefined) {
return this.itemTypes[ITEM_TYPES.competence]
}
return RdDItemCompetence.findCompetences(this.itemTypes[ITEM_TYPES.competence], name, options)
}
getCompetenceCorpsACorps(options = { onMessage: message => { } }) {
@@ -218,27 +226,24 @@ export class RdDBaseActorReve extends RdDBaseActor {
return this.getEmbeddedCollection("ActiveEffect").filter(filter);
}
getEffect(effectId) {
return this.getEmbeddedCollection("ActiveEffect").find(it => it.statuses?.has(effectId));
getEffectByStatus(statusId) {
return this.getEffects().find(it => it.statuses.has(statusId));
}
async setEffect(effectId, status) {
if (this.isEffectAllowed(effectId)) {
const effect = this.getEffect(effectId);
async setEffect(statusId, status) {
if (this.isEffectAllowed(statusId)) {
const effect = this.getEffectByStatus(statusId);
if (!status && effect) {
await this.deleteEmbeddedDocuments('ActiveEffect', [effect.id]);
}
if (status && !effect) {
await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(effectId)]);
await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(statusId)]);
}
}
}
async removeEffect(id) {
const effect = this.getEmbeddedCollection("ActiveEffect").find(it => it.id == id);
if (effect) {
await this.deleteEmbeddedDocuments('ActiveEffect', [id]);
}
this.removeEffects(it => it.id == id)
}
async removeEffects(filter = e => true) {
@@ -249,17 +254,16 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
/* -------------------------------------------- */
isDemiReve() {
return this.getEffectByStatus(STATUSES.StatusDemiReve) != undefined
}
getSurprise(isCombat = undefined) {
let niveauSurprise = this.getEffects()
.map(effect => StatusEffects.valeurSurprise(effect, isCombat))
.reduce(Misc.sum(), 0);
if (niveauSurprise > 1) {
return 'totale';
}
if (niveauSurprise == 1) {
return 'demi';
}
return '';
return StatusEffects.typeSurprise(
this.getEffects()
.map(it => StatusEffects.niveauSurprise(it, isCombat))
.reduce(Misc.sum(), 0)
)
}
/* -------------------------------------------- */
@@ -277,8 +281,20 @@ export class RdDBaseActorReve extends RdDBaseActor {
return dialog
}
createCallbackExperience() { return { action: r => { } } }
createCallbackAppelAuMoral() { return { action: r => { } } }
/* -------------------------------------------- */
createCallbackExperience() {
return { action: r => this.appliquerAjoutExperience(r) }
}
/* -------------------------------------------- */
createCallbackAppelAuMoral() {
/* Si l'appel au moral est utilisé, on l'affiche dans le chat et on diminue éventuellement le moral */
return { action: r => this.appliquerAppelMoral(r) }
}
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { }
async appliquerAppelMoral(rollData) { }
async _onCloseRollDialog(html) { }
@@ -433,9 +449,9 @@ export class RdDBaseActorReve extends RdDBaseActor {
* @param {*} categorieArme catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession
* @returns
*/
rollArme(arme, categorieArme, token) {
rollArme(arme, categorieArme = 'competence', token = undefined) {
token = token ?? RdDUtility.getSelectedToken(this)
const compToUse = this.$getCompetenceArme(arme, categorieArme)
const compToUse = RdDItemArme.getCompetenceArme(arme, categorieArme)
if (!RdDItemArme.isUtilisable(arme)) {
ui.notifications.warn(`Arme inutilisable: ${arme.name} a une résistance de 0 ou moins`)
return
@@ -469,10 +485,6 @@ export class RdDBaseActorReve extends RdDBaseActor {
})
}
$getCompetenceArme(arme, competenceName) {
return RdDItemArme.getCompetenceArme(arme, competenceName)
}
verifierForceMin(item) { }
/* -------------------------------------------- */

View File

@@ -292,7 +292,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
}
isSonne() {
return this.getEffect(STATUSES.StatusStunned)
return this.getEffectByStatus(STATUSES.StatusStunned)
}
isEffectAllowed(effectId) { return true }

View File

@@ -27,6 +27,7 @@ export class RdDBaseActor extends Actor {
}
return entry && entry.length > 0 ? carac[entry[0]] : undefined;
}
static getDefaultValue(actorType, path) {
if (path.includes('.')) {
path = path.split('.')
@@ -213,6 +214,7 @@ export class RdDBaseActor extends Actor {
isCreatureEntite() { return this.isCreature() || this.isEntite() }
isCreature() { return false }
isEntite(typeentite = []) { return false }
isHautRevant() { return false }
isVehicule() { return false }
isPersonnage() { return false }
getItem(id, type = undefined) {
@@ -742,6 +744,7 @@ export class RdDBaseActor extends Actor {
ui.notifications.info(`${this.getAlias()} ne peut pas faire cette action: ${action}`)
}
isAlcoolise() { return false }
async jetEthylisme() { this.actionImpossible("jet d'éthylisme") }
async rollAppelChance() { this.actionImpossible("appel à la chance") }
async jetDeMoral() { this.actionImpossible("jet de moral") }
@@ -754,18 +757,21 @@ export class RdDBaseActor extends Actor {
isActorCombat() { return false }
getCaracInit(competence) { return 0 }
listActionsCombat() { return [] }
listAttaques() {
return this.listActions({ isAttaque: true, isEquipe:false })
}
listActions({ isAttaque = false, isEquipe=false }) { return [] }
listActionsPossessions() {
return this.itemTypes[ITEM_TYPES.possession]
.map(p => {
return {
name: p.name,
action: 'possession',
system: {
competence: p.name,
possessionid: p.system.possessionid,
}
possessionid: p.system.possessionid,
}
})
}
}

View File

@@ -9,6 +9,7 @@ export class RdDActorExportSheet extends RdDActorSheet {
static init() {
foundry.applications.handlebars.loadTemplates([
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/arme.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/arme-titre.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/blessure.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/blessures.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs",
@@ -41,6 +42,7 @@ export class RdDActorExportSheet extends RdDActorSheet {
const formData = await super.getData()
// Add any structured, precomputed list of data
formData.context = Mapping.prepareContext(this.actor)
formData.attaques = this.actor.listActionsAttaque()
formData.export = this.getMappingValues(formData.context, this.actor)
formData.competences = this.getCompetences(CATEGORIES_COMPETENCES)
formData.draconic = this.getCompetences(CATEGORIES_DRACONIC)

View File

@@ -1,5 +1,5 @@
import { Grammar } from "../../grammar.js"
import { RdDItemArme } from "../../item-arme.js"
import { RdDItemArme } from "../../item/arme.js"
import { RdDItemCompetence } from "../../item-competence.js"
import { RdDItemSort } from "../../item-sort.js"
import { ITEM_TYPES } from "../../constants.js"
@@ -144,7 +144,7 @@ export class Mapping {
armes.push(RdDItemArme.corpsACorps(actor));
armes.push(RdDItemArme.empoignade(actor));
return armes.map(arme => [
arme.system.unemain ? Mapping.prepareArme(actor, arme, 'unemain') : undefined,
arme.system.unemain ? Mapping.prepareArme(actor, arme, '(1 main)') : undefined,
arme.system.deuxmains ? Mapping.prepareArme(actor, arme, 'deuxmains') : undefined,
!(arme.system.unemain || arme.system.deuxmains) ? Mapping.prepareArme(actor, arme, 'competence') : undefined,
arme.system.lancer != "" ? Mapping.prepareArme(actor, arme, 'lancer') : undefined,
@@ -256,8 +256,8 @@ export class Mapping {
static descriptionSort(sort) {
const ptSeuil = Array(sort.system.coutseuil).map(it => '*')
const caseTMR = sort.system.caseTMRspeciale.length > 0 ? Mapping.toVar(sort.system.caseTMRspeciale) : Misc.upperFirst(TMRType[sort.system.caseTMR].name)
const coutReve = 'r' + RdDItemSort.addSpaceToNonNumeric(sort.system.ptreve)
const diff = 'R' + RdDItemSort.addSpaceToNonNumeric(sort.system.difficulte)
const coutReve =RdDItemSort.coutReve(sort)
const diff = RdDItemSort.diffReve(sort)
return `${sort.name}${ptSeuil} (${caseTMR}) ${diff} ${coutReve}`
}
static toVar(caseSpeciale) {

View File

@@ -83,8 +83,8 @@ export class ChatUtility {
}
/* -------------------------------------------- */
static async createChatWithRollMode(messageData, actor = undefined) {
switch (game.settings.get("core", "rollMode")) {
static async createChatWithRollMode(messageData, actor = undefined, rollMode = game.settings.get("core", "rollMode")) {
switch (rollMode) {
case "blindroll": // GM only
if (!game.user.isGM) {
ChatUtility.blindMessageToGM(messageData)

View File

@@ -4,8 +4,7 @@ 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),
optionsFilter: options => options.editable,
filter: it => game.user.isGM || DialogEnchanter.isEnchantable(it) && it.parent?.type != ACTOR_TYPES.commerce,
action: (item, actor) => DialogEnchanter.enchanter(item)
}

View File

@@ -22,7 +22,7 @@ export class Grammar {
static equalsInsensitive(a, b) {
return Grammar.toLowerCaseNoAccent(a) == Grammar.toLowerCaseNoAccent(b)
}
static includesLowerCaseNoAccent(value, content) {
return Grammar.toLowerCaseNoAccent(value)?.includes(Grammar.toLowerCaseNoAccent(content));
}

7
module/initiative.mjs Normal file
View File

@@ -0,0 +1,7 @@
export class RdDInitiative {
static calculInitiative(niveau, caracValue, bonus = 0) {
let base = niveau + Math.floor(caracValue / 2) + bonus;
return "1d6" + (base >= 0 ? "+" : "") + base;
}
}

View File

@@ -103,8 +103,8 @@ export class RdDItemCompetence extends Item {
}
/* -------------------------------------------- */
static isMalusEncombrementTotal(competence) {
return competence?.name.toLowerCase().match(/(natation|acrobatie)/) || 0;
static isMalusEncombrementTotal(competenceName) {
return competenceName?.toLowerCase().match(/(natation|acrobatie)/) || 0;
}
/* -------------------------------------------- */

View File

@@ -1,7 +1,8 @@
import { ITEM_TYPES } from "./constants.js";
import { Grammar } from "./grammar.js";
import { RdDCombatManager } from "./rdd-combat.js";
import { RdDInitiative } from "./initiative.mjs";
import { RdDItem } from "./item.js";
export const CATEGORIES_COMPETENCES_CREATURES = {
"generale": { base: 0, label: "Générale" },
@@ -37,7 +38,7 @@ export class RdDItemCompetenceCreature extends Item {
competence: item.name,
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
niveau: item.system.niveau,
initiative: RdDCombatManager.calculInitiative(item.system.niveau, item.system.carac_value),
initiative: RdDInitiative.calculInitiative(item.system.niveau, item.system.carac_value),
equipe: true,
resistance: 100,
dommagesReels: item.system.dommages,
@@ -49,6 +50,41 @@ export class RdDItemCompetenceCreature extends Item {
}
return undefined;
}
static attaqueCreature(comp) {
const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(comp)
if (categorieAttaque != undefined) {
const initative = RdDInitiative.calculInitiative(comp.system.niveau, comp.system.carac_value);
return {
name: comp.name,
action: comp.isCompetencePossession() ? 'possession' : 'attaque',
initOnly: false,
arme: new RdDItem({
name: comp.name,
type: ITEM_TYPES.arme,
img: comp.img,
system: {
competence: comp.name,
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
niveau: comp.system.niveau,
initiative: initative,
equipe: true,
resistance: 100,
dommagesReels: comp.system.dommages,
penetration: 0,
force: 0,
rapide: true,
}
}),
comp: comp,
// main: '',
carac: { key: comp.name, value: comp.system.carac_value },
equipe: true,
dmg: comp.system.dommages,
initiative: initative
}
}
return undefined;
}
/* -------------------------------------------- */
static isAttaque(item) {

View File

@@ -16,13 +16,10 @@ export const VOIES_DRACONIC = [
/* -------------------------------------------- */
export class RdDItemSort extends Item {
static preloadHandlebars() {
Handlebars.registerHelper('itemSort-spaceIfText', val => RdDItemSort.addSpaceToNonNumeric(val))
Handlebars.registerHelper('itemSort-codeDraconic', voie => RdDItemSort.getCode(voie))
Handlebars.registerHelper('itemSort-shortDraconic', voie => RdDItemSort.getShortVoie(voie))
}
static addSpaceToNonNumeric(value) {
return Number.isNumeric(value) || ['-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].includes(String(value).charAt[0]) ? value : ' ' + RdDItemSort.toVar(value)
Handlebars.registerHelper('itemSort-diffReve', sort => RdDItemSort.diffReve(sort))
Handlebars.registerHelper('itemSort-coutReve', sort => RdDItemSort.coutReve(sort))
}
static lancements(sort) { return sort?.system.lancements.length ?? 0 }
@@ -43,21 +40,44 @@ export class RdDItemSort extends Item {
return value ? value.replace('variable', 'var') : ''
}
static isSortOnCoord(sort, coord) {
let tmr = TMRUtility.getTMR(coord)
const caseTMR = sort.system.caseTMR.toLowerCase();
const caseTMRspeciale = sort.system.caseTMRspeciale.toLowerCase();
return caseTMR.includes('variable')
|| caseTMRspeciale.includes('variable')
|| (caseTMR == tmr.type)
|| (caseTMR.includes('special') && caseTMRspeciale.includes(coord.toLowerCase()))
}
static getCaseTMR(sort) {
const caseTMR = sort.system.caseTMR.toLowerCase();
const caseTMRspeciale = sort.system.caseTMRspeciale.toLowerCase();
if (caseTMR.includes('variable') || caseTMRspeciale.includes('variable') || caseTMR.includes('special')) {
return sort.system.caseTMRspeciale
}
return sort.system.caseTMR
}
static diffReve(sort) { return RdDItemSort.toVar((sort.system.difficulte.match(/\-?(\d)+/) ? 'R' : 'R ') + sort.system.difficulte) }
static coutReve(sort) { return RdDItemSort.toVar((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)) {
case "lecture d'aura":
case "detection d'aura":
return competencesDraconic;
return competencesDraconic
case "annulation de magie":
return competencesDraconic.filter(it => !RdDItemCompetence.isThanatos(it));
return competencesDraconic.filter(it => !RdDItemCompetence.isThanatos(it))
}
const voies = sort.system.draconic.split('/')
return voies.map(voie => RdDItemCompetence.getVoieDraconic(competencesDraconic, voie))
}
static getBestDraconicSort(competencesDraconic, sort) {
return RdDItemSort.getDraconicsSort(competencesDraconic, sort).sort(Misc.descending(it => it.system.niveau)).find(it=>true)
return RdDItemSort.getDraconicsSort(competencesDraconic, sort).sort(Misc.descending(it => it.system.niveau)).find(it => true)
}
static getOrdreCode(code) {

View File

@@ -1,7 +1,8 @@
import { ITEM_TYPES } from "./constants.js";
import { DialogItemVente } from "./achat-vente/dialog-item-vente.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { DialogItemVente } from "./achat-vente/dialog-item-vente.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDUtility } from "./rdd-utility.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
@@ -84,6 +85,7 @@ export const defaultItemImg = {
/* -------------------------------------------- */
export class RdDItem extends Item {
static get defaultIcon() {
return undefined;
}
@@ -95,12 +97,12 @@ export class RdDItem extends Item {
static isFieldInventaireModifiable(type, field) {
switch (field) {
case 'quantite':
if ([ITEM_TYPES.conteneur].includes(type)) {
if (ITEM_TYPES.conteneur == type) {
return false;
}
break;
case 'cout':
if ([ITEM_TYPES.monnaie].includes(type)) {
if (ITEM_TYPES.monnaie == type) {
return game.user.isGM;
}
break;

View File

@@ -1,8 +1,10 @@
import { Grammar } from "./grammar.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"
import { ITEM_TYPES } from "./constants.js";
import { BASE_CORPS_A_CORPS } from "./item/base-items.js";
import { RdDCombatManager } from "./rdd-combat.js";
import { ITEM_TYPES } from "../constants.js";
import { RdDItem } from "../item.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js"
import { BASE_CORPS_A_CORPS } from "./base-items.js";
import { Grammar } from "../grammar.js";
import { RdDInitiative } from "../initiative.mjs";
const nomCategorieParade = {
"sans-armes": "Sans arme",
@@ -19,13 +21,17 @@ const nomCategorieParade = {
}
/* -------------------------------------------- */
export class RdDItemArme extends Item {
export class RdDItemArme extends RdDItem {
static isArme(item) {
return item.type == ITEM_TYPES.arme || RdDItemCompetenceCreature.getCategorieAttaque(item);
static get ITEM_TYPE() { return ITEM_TYPES.arme }
static get defaultIcon() {
return defaultItemImgArme
//return "systems/foundryvtt-reve-de-dragon/icons/armes_armure/epee_sord.webp";
}
/* -------------------------------------------- */
static getArme(arme) {
switch (arme ? arme.type : '') {
case ITEM_TYPES.arme: return arme;
@@ -42,10 +48,10 @@ export class RdDItemArme extends Item {
case ITEM_TYPES.arme:
switch (maniement) {
case 'competence': return arme.system.competence;
case 'unemain': return RdDItemArme.competence1Mains(arme);
case 'deuxmains': return RdDItemArme.competence2Mains(arme);
case 'tir': return arme.system.tir;
case 'lancer': return arme.system.lancer;
case '(1 main)': return arme.competence1Mains()
case '(2 mains)': return arme.competence2Mains()
case '(tir)': case 'tir': return arme.system.tir
case '(lancer)': case 'lancer': return arme.system.lancer;
}
}
return undefined
@@ -186,7 +192,7 @@ export class RdDItemArme extends Item {
return Number(arme.system.dommages)
}
const tableauDegats = arme.system.dommages.split("/");
return Number(tableauDegats[maniement == 'unemain' ? 0 : 1])
return Number(tableauDegats[maniement == '(1 main)' ? 0 : 1])
}
return Number(arme.system.dommages);
}
@@ -195,17 +201,17 @@ export class RdDItemArme extends Item {
static armeUneOuDeuxMains(arme, aUneMain) {
if (arme && !arme.system.cac) {
arme = foundry.utils.duplicate(arme);
arme.system.dommagesReels = RdDItemArme.dommagesReels(arme, aUneMain ? 'unemain' : 'deuxmains')
arme.system.dommagesReels = RdDItemArme.dommagesReels(arme, aUneMain ? '(1 main)' : '(2 mains)')
}
return arme;
}
static competence1Mains(arme) {
return arme.system.competence.replace(" 2 mains", " 1 main");
competence1Mains() {
return this.system.competence.replace(" 2 mains", " 1 main");
}
static competence2Mains(arme) {
return arme.system.competence.replace(" 1 main", " 2 mains");
competence2Mains() {
return this.system.competence.replace(" 1 main", " 2 mains");
}
static isUtilisable(arme) {
@@ -218,10 +224,8 @@ export class RdDItemArme extends Item {
static isAttaque(arme) {
switch (arme.type) {
case ITEM_TYPES.arme:
return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0)
case ITEM_TYPES.competencecreature:
return arme.system.iscombat && RdDItemCompetenceCreature.isAttaque(item)
case ITEM_TYPES.arme: return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0)
case ITEM_TYPES.competencecreature: return arme.system.iscombat && RdDItemCompetenceCreature.isAttaque(item)
}
return false
}
@@ -229,23 +233,24 @@ export class RdDItemArme extends Item {
static isParade(arme) {
switch (arme.type) {
case ITEM_TYPES.arme:
return arme.system.equipe && arme.system.resistance > 0 && true/* TODO: regarder la categorie d'arme?*/
return arme.system.resistance > 0 && true/* TODO: regarder la categorie d'arme?*/
case ITEM_TYPES.competencecreature:
return arme.system.iscombat && RdDItemCompetenceCreature.isParade(arme)
}
return false
}
static corpsACorps(actor) {
let competence = actor?.getCompetenceCorpsACorps() ?? BASE_CORPS_A_CORPS
let melee = actor ? actor.system.carac['melee'].value : 0
return {
return new RdDItemArme({
_id: competence.id,
name: 'Corps à corps',
type: ITEM_TYPES.arme,
img: competence.img,
system: {
initiative: RdDCombatManager.calculInitiative(competence.system.niveau, melee),
initiative: RdDInitiative.calculInitiative(competence.system.niveau, melee),
equipe: true,
rapide: true,
force: 0,
@@ -259,7 +264,7 @@ export class RdDItemArme extends Item {
deuxmains: true,
categorie_parade: 'sans-armes'
}
}
})
}
static mainsNues(actor) {

View File

@@ -3,8 +3,6 @@ import { Misc } from "../misc.js"
import { RdDSheetUtility } from "../rdd-sheet-utility.js"
import { RdDUtility } from "../rdd-utility.js"
/**
* TODO:
* options.editable ?
@@ -15,21 +13,21 @@ const _SPACEHOLDER = { placeholder: true }
const _VENDRE = {
code: 'item-vendre', label: 'Vendre ou donner', icon: it => 'fa-solid fa-comments-dollar',
filter: it => Misc.toInt(it.system.quantite) > 0,
optionsFilter: options => options.editable,
action: (item, actor) => item.proposerVente()
}
const _ACHAT_SERVICE = {
code: 'item-service-acheter', label: 'Acheter', icon: it => 'fa-regular fa-coins',
const _ACHETER = {
code: 'item-acheter', label: 'Acheter', icon: it => 'fa-regular fa-coins',
filter: it => Misc.toInt(it.system.quantite) > 0 && it.parent?.type == ACTOR_TYPES.commerce,
action: (item, actor) => actor.vente(item)
}
const _MONTRER = {
code: 'item-montrer', label: 'Montrer', icon: it => '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',
filter: it => Misc.toInt(it.system.quantite) > 1,
filter: it => Misc.toInt(it.system.quantite) > 1 && it.parent?.type != ACTOR_TYPES.commerce,
action: (item, actor) => RdDSheetUtility.splitItem(item, actor)
}
@@ -39,7 +37,7 @@ const _EDIT = {
}
const _DELETE = {
code: 'item-delete', label: 'Supprimer', icon: it => 'fa-solid fa-trash',
optionsFilter: options => options.editable && options.isOwner,
optionsFilter: options => options.isOwner,
action: (item, actor) => RdDUtility.confirmActorItemDelete(item, actor)
}
const _EQUIPER = {
@@ -51,30 +49,25 @@ const _EQUIPER = {
const _CUISINER = {
code: 'item-cuisiner', label: 'Cuisiner', icon: it => 'fa-solid fa-utensils',
filter: it => it.getUtilisation() == 'cuisine' && it.system.sust > 0,
optionsFilter: options => options.editable,
action: (item, actor) => actor.preparerNourriture(item)
}
const _MANGER_CRU = {
code: 'item-manger-cru', label: 'Manger cru', icon: it => 'fa-solid fa-drumstick-bite',
filter: it => it.getUtilisation() == 'cuisine' && it.system.sust > 0,
optionsFilter: options => options.editable,
action: (item, actor) => actor.mangerNourriture(item)
}
const _MANGER = {
code: 'item-manger', label: 'Manger', icon: it => 'fa-solid fa-utensils',
filter: it => !(it.system.boisson),
optionsFilter: options => options.editable,
action: (item, actor) => actor.mangerNourriture(item)
}
const _BOIRE = {
code: 'item-boire', label: 'Boire', icon: it => 'fa-solid fa-glass-water',
filter: it => it.system.boisson,
optionsFilter: options => options.editable,
action: (item, actor) => actor.mangerNourriture(item)
}
const _DECOCTION = {
code: 'item-decoction', label: 'Décoction', icon: it => 'fa-solid fa-flask-vial',
optionsFilter: options => options.editable,
action: (item, actor) => actor.fabriquerDecoctionHerbe(item)
}
const _OUVRIR = {
@@ -84,14 +77,12 @@ const _OUVRIR = {
const _LIRE = {
code: 'item-lire', label: 'Lire', icon: it => 'fa-solid fa-book-open',
optionsFilter: options => options.editable,
action: (item, actor) => actor.actionLire(item)
}
const _REFOULER = {
code: 'item-refouler', label: 'Refouler', icon: it => 'fa-solid fa-burst',
filter: it => it.system.refoulement > 0,
optionsFilter: options => options.editable,
action: (item, actor) => actor.actionRefoulement(item)
}
@@ -102,7 +93,7 @@ const _SORT_RESERVE = {
}
export const COMMON_ACTIONS = [_EQUIPER]
export const DEFAULT_ACTIONS = [_SPACEHOLDER, _SPLIT, _VENDRE, _MONTRER, _EDIT, _DELETE]
export const DEFAULT_ACTIONS = [_ACHETER, _SPACEHOLDER, _SPLIT, _VENDRE, _MONTRER, _EDIT, _DELETE]
export const ITEM_ACTIONS = {
faune: [_CUISINER, _MANGER_CRU],
@@ -114,17 +105,16 @@ export const ITEM_ACTIONS = {
ombre: [_REFOULER],
plante: [_CUISINER, _MANGER_CRU],
queue: [_REFOULER],
sort: [_SORT_RESERVE],
service: [_ACHAT_SERVICE]
sort: [_SORT_RESERVE]
}
export class ItemAction {
static applies(action, item, options) {
return action && item
&& item.isActionAllowed(action.code)
&& (!action.filter || action.filter(item))
&& (action.allowLimited || options.editable)
&& (!action.optionsFilter || action.optionsFilter(options))
}
@@ -136,10 +126,10 @@ export class ItemAction {
}
static async onActionItem(event, actor, options) {
const item = RdDSheetUtility.getItem(event, actor)
const code = $(event.currentTarget).data('code')
const item = RdDSheetUtility.getItem(event, actor)
const action = item?.itemActions().find(it => it.code == code)
if (action && (!action.optionsFilter || action.optionsFilter(options))) {
if (action && ItemAction.applies(action, item, options)) {
await action.action(item, actor)
}
}

View File

@@ -5,7 +5,7 @@ import { RdDRaretes } from "./raretes.js";
const TYPE_ITEMS_NATURELS = ["faune", "herbe", "plante", "ingredient"];
export class RdDItemInventaireSheet extends RdDItemSheetV1 {
export class RdDInventaireItemSheet extends RdDItemSheetV1 {
static get defaultOptions() {
return foundry.utils.mergeObject(RdDItemSheetV1.defaultOptions, {

View File

@@ -2,9 +2,9 @@ import { RdDBaseActorSheet } from "../actor/base-actor-sheet.js";
import { ITEM_TYPES } from "../constants.js";
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
import { RdDUtility } from "../rdd-utility.js";
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
import { RdDInventaireItemSheet } from "./sheet-base-inventaire.js";
export class RdDConteneurItemSheet extends RdDItemInventaireSheet {
export class RdDConteneurItemSheet extends RdDInventaireItemSheet {
static get ITEM_TYPE() { return ITEM_TYPES.conteneur };

View File

@@ -1,6 +1,6 @@
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
import { RdDInventaireItemSheet } from "./sheet-base-inventaire.js";
export class RdDFauneItemSheet extends RdDItemInventaireSheet {
export class RdDFauneItemSheet extends RdDInventaireItemSheet {
static get ITEM_TYPE() { return "faune" };

View File

@@ -2,9 +2,9 @@ import { ITEM_TYPES } from "../constants.js";
import { DialogEnchanter } from "../enchantement/dialog-enchanter.js";
import { RdDTimestamp } from "../time/rdd-timestamp.js";
import { RdDItemGemme } from "./gemme.js";
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
import { RdDInventaireItemSheet } from "./sheet-base-inventaire.js";
export class RdDGemmeItemSheet extends RdDItemInventaireSheet {
export class RdDGemmeItemSheet extends RdDInventaireItemSheet {
static get ITEM_TYPE() { return ITEM_TYPES.gemme };

View File

@@ -1,6 +1,6 @@
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
import { RdDInventaireItemSheet } from "./sheet-base-inventaire.js";
export class RdDHerbeItemSheet extends RdDItemInventaireSheet {
export class RdDHerbeItemSheet extends RdDInventaireItemSheet {
static get ITEM_TYPE() { return "herbe" };
}

View File

@@ -1,5 +1,5 @@
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
import { RdDInventaireItemSheet } from "./sheet-base-inventaire.js";
export class RdDIngredientItemSheet extends RdDItemInventaireSheet {
export class RdDIngredientItemSheet extends RdDInventaireItemSheet {
static get ITEM_TYPE() { return "ingredient" };
}

View File

@@ -1,6 +1,6 @@
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
import { RdDInventaireItemSheet } from "./sheet-base-inventaire.js";
export class RdDPlanteItemSheet extends RdDItemInventaireSheet {
export class RdDPlanteItemSheet extends RdDInventaireItemSheet {
static get ITEM_TYPE() { return "plante" };

View File

@@ -2,10 +2,10 @@ import { ITEM_TYPES } from "../constants.js";
import { DialogEnchanter } from "../enchantement/dialog-enchanter.js";
import { RdDTimestamp } from "../time/rdd-timestamp.js";
import { RdDItemPotion } from "./potion.js";
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
import { RdDInventaireItemSheet } from "./sheet-base-inventaire.js";
export class RdDPotionItemSheet extends RdDItemInventaireSheet {
export class RdDPotionItemSheet extends RdDInventaireItemSheet {
static get ITEM_TYPE() { return ITEM_TYPES.potion };

View File

@@ -8,7 +8,6 @@ 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 { Misc } from "./misc.js";
class Migration {
get code() { return "sample"; }
@@ -248,7 +247,7 @@ class _10_2_10_DesirLancinant_IdeeFixe extends Migration {
await this.applyItemsUpdates(items => items
.filter(it => ['queue', 'ombre'].includes(it.type))
.map(it => this.migrateQueue(it))
);
)
}
}
@@ -632,7 +631,7 @@ class _12_0_38_TachesEcriture extends Migration {
async migrate() {
await this.applyItemsUpdates(items => items
.filter(it => [ITEM_TYPES.tache, ITEM_TYPES.livre, ITEM_TYPES.oeuvre, ITEM_TYPES.meditation].includes(it.type) )
.filter(it => [ITEM_TYPES.tache, ITEM_TYPES.livre, ITEM_TYPES.oeuvre, ITEM_TYPES.meditation].includes(it.type))
.filter(it => Grammar.equalsInsensitive(it.system.competence, 'ecriture'))
.map(it => { return { _id: it.id, 'system.competence': 'Écriture' } })
)
@@ -640,11 +639,26 @@ class _12_0_38_TachesEcriture extends Migration {
}
class _13_0_4_FixReveActuel extends Migration {
get code() { return "fix-revvve-actuel" }
get code() { return "fix-reve-actuel" }
get version() { return "13.0.4" }
async migrate() {
game.actors.forEach(it => it.update({'system.carac.-=reve-actuel': null}))
game.actors.forEach(it => it.update({ 'system.carac.-=reve-actuel': null }))
}
}
class _13_0_7_FixNiveauOeuvres extends Migration {
get code() { return "fix-niveau-oeuvres" }
get version() { return "13.0.7" }
async migrate() {
await this.applyItemsUpdates(items => items
.filter(it => [ITEM_TYPES.musique, ITEM_TYPES.chant, ITEM_TYPES.danse, ITEM_TYPES.recettecuisine].includes(it.type))
.map(it => {
const niveau = isNaN(it.system.niveau) ? 0 : parseInt(it.system.niveau)
return { _id: it.id, 'system.niveau': niveau }
})
)
}
}
@@ -671,7 +685,8 @@ export class Migrations {
new _12_0_32_MigrationRaces(),
new _12_0_37_MigrationAlchimieEtat(),
new _12_0_38_TachesEcriture(),
new _13_0_4_FixReveActuel()
new _13_0_4_FixReveActuel(),
new _13_0_7_FixNiveauOeuvres(),
];
}

View File

@@ -38,6 +38,12 @@ export class Misc {
return (a, b) => Number(a) + Number(b);
}
static and(predicates) {
return value => predicates.map(predicate => predicate(value))
.reduce((v1, v2) => v1 && v2, true);
}
static ascending(orderFunction = x => x) {
return (a, b) => Misc.sortingBy(orderFunction(a), orderFunction(b));
}
@@ -60,6 +66,11 @@ export class Misc {
static arrayOrEmpty(items) {
return items?.length ? items : [];
}
static findOrFirst(list, predicate) {
return list.find(predicate) ?? list[0]
}
/**
* Converts the value to an integer, or to 0 if undefined/null/not representing integer
* @param {*} value value to convert to an integer using parseInt
@@ -75,13 +86,17 @@ export class Misc {
return Math.round(num * power10n) / power10n;
}
static getFractionHtml(diviseur) {
if (!diviseur || diviseur <= 1) return undefined;
switch (diviseur || 1) {
case 2: return '&frac12;';
case 4: return '&frac14;';
default: return '1/' + diviseur;
static getFractionOneN(divider) {
if (!divider || divider == 1) {
return 1
}
switch (divider) {
case 2: return '&frac12;'
case 4: return '&frac14;'
case 8: return '&frac18;'
}
return `1/${divider}`
}
static indexLowercase(list) {
@@ -216,7 +231,7 @@ export class Misc {
static isFirstConnectedGM() {
return game.user == Misc.firstConnectedGM();
}
static hasConnectedGM() {
return Misc.firstConnectedGM();
}

View File

@@ -37,21 +37,37 @@ const TABLE_CARACTERISTIQUES_DERIVEES = {
32: { xp: 180, niveau: 11, poids: "1501-2000", poidsMin: 1501, poidsMax: 2000, plusdom: +11, sconst: 10, sust: 17 }
};
export const CARACS = {
TAILLE: 'taille',
APPARENCE: 'apparence',
CONSTITUTION: 'constitution',
FORCE: 'force',
AGILITE: 'agilite',
DEXTERITE: 'dexterite',
VUE: 'vue',
OUIE: 'ouie',
ODORATGOUT: 'odoratgout',
VOLONTE: 'volonte',
INTELLECT: 'intellect',
EMPATHIE: 'empathie',
REVE: 'reve',
CHANCE: 'chance',
}
export const LIST_CARAC_PERSONNAGE = {
'taille': { code: 'taille', label: 'Taille', isCarac: true, path: 'system.carac.taille.value' },
'apparence': { code: 'apparence', label: 'Apparence', isCarac: true, path: 'system.carac.apparence.value' },
'constitution': { code: 'constitution', label: 'Constitution', isCarac: true, path: 'system.carac.constitution.value' },
'force': { code: 'force', label: 'Force', isCarac: true, path: 'system.carac.force.value' },
'agilite': { code: 'agilite', label: 'Agilité', isCarac: true, path: 'system.carac.agilite.value' },
'dexterite': { code: 'dexterite', label: 'Dextérité', isCarac: true, path: 'system.carac.dexterite.value' },
'vue': { code: 'vue', label: 'Vue', isCarac: true, path: 'system.carac.vue.value' },
'ouie': { code: 'ouie', label: 'Ouïe', isCarac: true, path: 'system.carac.ouie.value' },
'odoratgout': { code: 'odoratgout', label: 'Odorat-Goût', isCarac: true, path: 'system.carac.odoratgout.value' },
'volonte': { code: 'volonte', label: 'Volonté', isCarac: true, path: 'system.carac.volonte.value' },
'intellect': { code: 'intellect', label: 'Intellect', isCarac: true, path: 'system.carac.intellect.value' },
'empathie': { code: 'empathie', label: 'Empathie', isCarac: true, path: 'system.carac.empathie.value' },
'reve': { code: 'reve', label: 'Rêve', isCarac: true, path: 'system.carac.reve.value' },
'chance': { code: 'chance', label: 'Chance', isCarac: true, path: 'system.carac.chance.value' },
[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' },
[CARACS.CONSTITUTION]: { code: CARACS.CONSTITUTION, label: 'Constitution', isCarac: true, path: 'system.carac.constitution.value' },
[CARACS.FORCE]: { code: CARACS.FORCE, label: 'Force', isCarac: true, path: 'system.carac.force.value' },
[CARACS.AGILITE]: { code: CARACS.AGILITE, label: 'Agilité', isCarac: true, path: 'system.carac.agilite.value' },
[CARACS.DEXTERITE]: { code: CARACS.DEXTERITE, label: 'Dextérité', isCarac: true, path: 'system.carac.dexterite.value' },
[CARACS.VUE]: { code: CARACS.VUE, label: 'Vue', isCarac: true, path: 'system.carac.vue.value' },
[CARACS.OUIE]: { code: CARACS.OUIE, label: 'Ouïe', isCarac: true, path: 'system.carac.ouie.value' },
[CARACS.ODORATGOUT]: { code: CARACS.ODORATGOUT, label: 'Odorat-Goût', isCarac: true, path: 'system.carac.odoratgout.value' },
[CARACS.VOLONTE]: { code: CARACS.VOLONTE, label: 'Volonté', isCarac: true, path: 'system.carac.volonte.value' },
[CARACS.INTELLECT]: { code: CARACS.INTELLECT, label: 'Intellect', isCarac: true, path: 'system.carac.intellect.value' },
[CARACS.EMPATHIE]: { code: CARACS.EMPATHIE, label: 'Empathie', isCarac: true, path: 'system.carac.empathie.value' },
[CARACS.REVE]: { code: CARACS.REVE, label: 'Rêve', isCarac: true, path: 'system.carac.reve.value' },
[CARACS.CHANCE]: { code: CARACS.CHANCE, label: 'Chance', isCarac: true, path: 'system.carac.chance.value' },
'protection': { code: 'protection', label: 'Protection naturelle', isCarac: false, path: 'system.attributs.protection.value' },
'beaute': { code: 'beaute', label: 'Beauté', isCarac: false, path: 'system.background.beaute.value' }
}
@@ -69,7 +85,7 @@ const LIST_CARAC_DERIVEE = {
'reve-actuel': { code: "reve-actuel", label: 'Rêve actuel', path: 'system.reve.reve.value' },
}
const LIST_CARAC_ROLL = Object.values(LIST_CARAC_PERSONNAGE).filter(it => it.isCarac && it.code != 'taille')
export const LIST_CARAC_ROLL = Object.values(LIST_CARAC_PERSONNAGE).filter(it => it.isCarac && it.code != 'taille')
.concat(Object.values(LIST_CARAC_AUTRES))
.concat(Object.values(LIST_CARAC_DERIVEE))
@@ -95,27 +111,41 @@ export class RdDCarac {
return Object.values(LIST_CARAC_PERSONNAGE).filter(filter)
}
static isAgiliteOuDerobee(selectedCarac) {
return selectedCarac?.label.match(/(Agilité|Dérobée)/);
static isAgiliteOuDerobee(caracLabel) {
return RdDCarac.isAgilite(caracLabel)
|| RdDCarac.isDerobee(caracLabel)
}
static isVolonte(selectedCarac) {
return selectedCarac?.label == 'Volonté';
static isDerobee(caracLabel) {
return Grammar.equalsInsensitive(caracLabel, LIST_CARAC_PERSONNAGE.agilite.code);
}
static isChance(selectedCarac) {
return selectedCarac?.label?.toLowerCase()?.match(/chance( actuelle)?/);
static isAgilite(caracLabel) {
return Grammar.equalsInsensitive(caracLabel, LIST_CARAC_DERIVEE.derobee.code);
}
static isReve(selectedCarac) {
return selectedCarac?.label?.toLowerCase()?.match(/r(e|ê)ve(( |-)actuel)?/);
static isIntellect(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel) == 'intellect';
}
static isVolonte(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel) == 'volonte';
}
static isChance(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel)?.match(/chance(( |-)?actuelle)?/);
}
static isReve(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel)?.match(/reve(( |-)?actuel)?/);
}
/**
* Lappel à la chance nest possible que pour recommencer les jets dactions physiques :
* tous les jets de combat, de FORCE, dAGILITÉ, de DEXTÉRITÉ, de Dérobée, dAPPARENCE,
* ainsi que de Perception active et volontaire.
* Le moral ne s'utilise aussi que sur les actions physiques
*/
static isActionPhysique(selectedCarac) {
return Grammar.toLowerCaseNoAccent(selectedCarac?.label)
static isActionPhysique(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel)
?.match(/(apparence|force|agilite|dexterite|vue|ouie|gout|odorat|empathie|melee|tir|lancer|derobee)/) != null
}

View File

@@ -1,9 +1,6 @@
import { ChatUtility } from "./chat-utility.js";
import { ENTITE_BLURETTE, HIDE_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { Grammar } from "./grammar.js";
import { RdDItemArme } from "./item-arme.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { Misc } from "./misc.js";
import { RdDBonus } from "./rdd-bonus.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
@@ -14,26 +11,30 @@ import { STATUSES } from "./settings/status-effects.js";
import { Targets } from "./targets.js";
import { RdDEmpoignade } from "./rdd-empoignade.js";
import { RdDRollResult } from "./rdd-roll-result.js";
import { RdDItemArme } from "./item/arme.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { RdDInitiative } from "./initiative.mjs";
/* -------------------------------------------- */
const premierRoundInit = [
{ pattern: 'hast', init: 5.90 },
{ pattern: 'lance', init: 5.85 },
{ pattern: 'baton', init: 5.80 },
{ pattern: 'doubledragonne', init: 5.75 },
{ pattern: 'esparlongue', init: 5.70 },
{ pattern: 'epeedragonne', init: 5.65 },
{ pattern: 'epeebatarde', init: 5.60 },
{ pattern: 'epeecyane', init: 5.55 },
{ pattern: 'epeesorde', init: 5.50 },
{ pattern: 'grandehache', init: 5.45 },
{ pattern: 'bataille', init: 5.40 },
{ pattern: 'epeegnome', init: 5.35 },
{ pattern: 'masse', init: 5.30 },
{ pattern: 'gourdin', init: 5.25 },
{ pattern: 'fleau', init: 5.20 },
{ pattern: 'dague', init: 5.15 },
{ pattern: 'autre', init: 5.10 },
{ pattern: 'hast' },
{ pattern: 'lance' },
{ pattern: 'baton' },
{ pattern: 'doubledragonne' },
{ pattern: 'esparlongue' },
{ pattern: 'epeedragonne' },
{ pattern: 'epeebatarde' },
{ pattern: 'epeecyane' },
{ pattern: 'epeesorde' },
{ pattern: 'grandehache' },
{ pattern: 'bataille' },
{ pattern: 'epeegnome' },
{ pattern: 'masse' },
{ pattern: 'gourdin' },
{ pattern: 'fleau' },
{ pattern: 'dague' },
{ pattern: 'autre' },
];
/* -------------------------------------------- */
@@ -45,6 +46,10 @@ export class RdDCombatManager extends Combat {
Hooks.on("updateCombat", (combat, change, options, userId) => { RdDCombat.onUpdateCombat(combat, change, options, userId) });
Hooks.on("preDeleteCombat", (combat, html, id) => { combat.onPreDeleteCombat() })
Hooks.on("deleteCombat", (combat, html, id) => { combat.onDeleteCombat() })
for (let i = 0.0; i < premierRoundInit.length; i++) {
premierRoundInit[i].init = 5.99 - i / 100
}
}
/* -------------------------------------------- */
@@ -108,9 +113,7 @@ export class RdDCombatManager extends Combat {
async rollInitiative(ids, messageOptions = {}) {
console.log(`${game.system.title} | Combat.rollInitiative()`, ids, messageOptions)
ids = typeof ids === "string" ? [ids] : ids
ids.forEach(async id =>
await this.rollInitRdD(id, undefined, messageOptions)
)
Promise.all(ids.map(id => this.rollInitRdD(id, undefined, messageOptions)))
return this
}
@@ -148,7 +151,7 @@ export class RdDCombatManager extends Combat {
}
static getFirstInitRollFormula(actor) {
const actions = actor.listActionsCombat()
const actions = actor.listActions({ isEquipe: true })
if (actions.length > 0) {
const action = actions[0]
const init = RdDCombatManager.getInitData(actor, action)
@@ -161,87 +164,7 @@ export class RdDCombatManager extends Combat {
}
static formuleInitiative(rang, carac, niveau, bonusMalus) {
return `${rang} +( (${RdDCombatManager.calculInitiative(niveau, carac, bonusMalus)} )/100)`;
}
/* -------------------------------------------- */
static calculInitiative(niveau, caracValue, bonus = 0) {
let base = niveau + Math.floor(caracValue / 2) + bonus;
return "1d6" + (base >= 0 ? "+" : "") + base;
}
/* -------------------------------------------- */
/** Retourne une liste triée d'actions d'armes avec le split arme1 main / arme 2 main / lancer */
static listActionsArmes(armes, competences, carac) {
let actions = [];
for (const arme of armes) {
if (arme.system.equipe) {
const dommages = arme.system.dommages.toString();
const tableauDommages = dommages.includes("/") ? dommages.split("/") : [dommages, dommages];
if (arme.system.unemain && arme.system.deuxmains && !dommages.includes("/")) {
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + arme.name + " ne sont pas corrects (ie sous la forme X/Y)");
}
if (arme.system.unemain && arme.system.competence) {
actions.push(RdDCombatManager.$prepareAttaqueArme({
arme: arme,
infoMain: "(1 main)",
dommagesReel: Number(tableauDommages[0]),
competence: arme.system.competence,
carac: carac,
competences: competences
}));
}
if (arme.system.deuxmains && arme.system.competence) {
actions.push(RdDCombatManager.$prepareAttaqueArme({
arme: arme,
infoMain: "(2 mains)",
dommagesReel: Number(tableauDommages[1]),
competence: RdDItemArme.competence2Mains(arme),
carac: carac,
competences: competences
}));
}
if (arme.system.lancer) {
actions.push(RdDCombatManager.$prepareAttaqueArme({
arme: arme,
infoMain: "(lancer)",
dommagesReel: Number(tableauDommages[0]),
competence: arme.system.lancer,
carac: carac,
competences: competences
}));
}
if (arme.system.tir) {
actions.push(RdDCombatManager.$prepareAttaqueArme({
arme: arme,
infoMain: "(tir)",
dommagesReel: Number(tableauDommages[0]),
competence: arme.system.tir,
carac: carac,
competences: competences
}));
}
}
}
return actions.sort(Misc.ascending(action => action.name + (action.system.infoMain ?? '')));
}
static $prepareAttaqueArme(infoAttaque) {
const comp = infoAttaque.competences.find(it => Grammar.equalsInsensitive(it.name, infoAttaque.competence))
const arme = infoAttaque.arme;
const attaque = foundry.utils.duplicate(arme)
const carac = comp?.system.defaut_carac ?? (infoAttaque.infoMain == '(lancer)' ? 'lancer' : infoAttaque.infoMain == '(lancer)' ? 'tir' : 'melee')
const niveau = comp?.system.niveau ?? (infoAttaque.infoMain == '(lancer)' ? -8 : -6)
attaque.action = 'attaque';
attaque.system.competence = infoAttaque.competence;
attaque.system.dommagesReels = infoAttaque.dommagesReel;
attaque.system.infoMain = infoAttaque.infoMain;
attaque.system.niveau = niveau
const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + (arme.system.magique) ? arme.system.ecaille_efficacite : 0
attaque.system.initiative = RdDCombatManager.calculInitiative(niveau, infoAttaque.carac[carac].value, ajustement)
return attaque
return `${rang} +( (${RdDInitiative.calculInitiative(niveau, carac, bonusMalus)} )/100)`;
}
/* -------------------------------------------- */
@@ -251,19 +174,20 @@ export class RdDCombatManager extends Combat {
let initMissing = game.combat.combatants.find(it => !it.initiative);
if (!initMissing) { // Premier round !
for (let combatant of game.combat.combatants) {
let action = combatant.initiativeData?.arme;
//console.log("Parsed !!!", combatant, initDone, game.combat.current, arme);
if (action && action.type == "arme") {
for (let initData of premierRoundInit) {
if (Grammar.toLowerCaseNoAccentNoSpace(action.system.initpremierround).includes(initData.pattern)) {
let msg = `<h4>L'initiative de ${combatant.actor.getAlias()} a été modifiée !</h4>
if (combatant.initiativeData?.arme?.type == "arme") {
// TODO: get init data premier round
const initiativeData = combatant.initiativeData;
const action = combatant.initiativeData.arme;
const fromArme = Grammar.toLowerCaseNoAccentNoSpace(action.system.initpremierround)
const initData = premierRoundInit.find(it => fromArme.includes(initData.pattern))
if (initData) {
let msg = `<h4>L'initiative de ${combatant.actor.getAlias()} a été modifiée !</h4>
<hr>
<div>
Etant donné son ${action.name}, son initative pour ce premier round est désormais de ${initData.init}.
</div>`
ChatMessage.create({ content: msg });
game.combat.setInitiative(combatant._id, initData.init);
}
ChatMessage.create({ content: msg });
game.combat.setInitiative(combatant._id, initData.init);
}
}
}
@@ -297,7 +221,7 @@ export class RdDCombatManager extends Combat {
].concat(options);
}
/* -------------------------------------------- */
static rollInitiativeAction(combatantId, action) {
static async rollInitiativeAction(combatantId, action) {
const combatant = game.combat.combatants.get(combatantId)
const actor = RdDCombatManager.getActorCombatant(combatant)
if (actor == undefined) { return [] }
@@ -305,10 +229,11 @@ export class RdDCombatManager extends Combat {
combatant.initiativeData = { arme: action } // pour reclasser l'init au round 0
const init = RdDCombatManager.getInitData(actor, action)
const ajustement = RdDCombatManager.calculAjustementInit(actor, action)
const ajustement = RdDCombatManager.calculAjustementInit(actor, action.arme)
const rollFormula = RdDCombatManager.formuleInitiative(init.offset, init.carac, init.niveau, ajustement);
game.combat.rollInitRdD(combatantId, rollFormula, init);
await game.combat.rollInitRdD(combatantId, rollFormula, init);
combatant.initiativeData
}
static getInitData(actor, action) {
@@ -318,12 +243,12 @@ export class RdDCombatManager extends Combat {
if (action.action == 'possession') { return { offset: 10, info: "Possession", carac: actor.getReveActuel(), niveau: 0 } }
if (action.action == 'haut-reve') { return { offset: 9, info: "Draconic", carac: actor.getReveActuel(), niveau: 0 } }
const comp = RdDItemCompetence.findCompetence(actor.items, action.system.competence);
const comp = action.comp
return {
offset: RdDCombatManager.initOffset(comp?.system.categorie, action),
info: action.name + " / " + action.system.competence,
offset: RdDCombatManager.initOffset(comp?.system.categorie, action.arme),
info: action.name + " / " + comp.name,
carac: actor.getCaracInit(comp),
niveau: comp?.system.niveau ?? -8
niveau: comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(action.main) ? -8 : -6)
}
}
@@ -366,7 +291,7 @@ export class RdDCombatManager extends Combat {
const possessions = actor.listActionsPossessions()
const actions = possessions.length > 0
? possessions
: actor.listActionsCombat()
: actor.listActions({ isEquipe: true })
for (let index = 0; index < actions.length; index++) {
actions[index].index = index
@@ -710,8 +635,9 @@ export class RdDCombat {
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 (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 };
}
@@ -775,7 +701,7 @@ export class RdDCombat {
// sans armes: à mains nues
rollData.arme = RdDItemArme.corpsACorps(this.attacker)
rollData.arme.system.niveau = competence.system.niveau
rollData.arme.system.initiative = RdDCombatManager.calculInitiative(competence.system.niveau, this.attacker.system.carac['melee'].value);
rollData.arme.system.initiative = RdDInitiative.calculInitiative(competence.system.niveau, this.attacker.system.carac['melee'].value);
}
return rollData;
}
@@ -1141,7 +1067,7 @@ export class RdDCombat {
if (RdDCombat.isParticuliere(defenderRoll)) {
await this._onEsquiveParticuliere(defenderRoll)
}
return
return
}
return await this._onEsquiveEchec(defenderRoll)
}

View File

@@ -1,4 +1,4 @@
import { RdDItemArme } from "./item-arme.js";
import { RdDItemArme } from "./item/arme.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { ITEM_TYPES } from "./constants.js";
@@ -22,13 +22,12 @@ export class RdDHotbar {
static $macroNameSuffix(armeCompetence) {
switch (armeCompetence) {
case 'unemain': return ' (1 main)';
case 'deuxmains': return ' (2 main)';
case '(1 main)': return ' (1 main)';
case '(2 mains)': return ' (2 main)';
case 'tir': return ' (tir)';
case 'lancer': return ' (lancer)';
case 'pugilat': return ' (pugilat)';
case 'empoignade': return ' (empoignade)';
}
return ''
}
@@ -40,10 +39,10 @@ export class RdDHotbar {
// Les armes peuvent avoir plusieurs usages
if (item.system.competence != '') {
if (item.system.unemain) {
await this.createItemMacro(item, slot++, 'unemain')
await this.createItemMacro(item, slot++, '(1 main)')
}
if (item.system.deuxmains) {
await this.createItemMacro(item, slot++, 'deuxmains')
await this.createItemMacro(item, slot++, '(2 mains)')
}
}
if (item.system.lancer != '') {
@@ -121,9 +120,9 @@ export class RdDHotbar {
if (item.isCorpsACorps()) {
switch (categorieArme) {
case 'pugilat':
return actor.rollArme(RdDItemArme.corpsACorps(actor), 'competence');
return actor.rollArme(RdDItemArme.corpsACorps(actor));
case 'empoignade':
return actor.rollArme(RdDItemArme.empoignade(actor), 'competence');
return actor.rollArme(RdDItemArme.empoignade(actor));
}
}
return actor.rollCompetence(item);

View File

@@ -1,5 +1,4 @@
import { SYSTEM_RDD, SYSTEM_SOCKET_ID, RDD_CONFIG } from "./constants.js"
import { Migrations } from './migrations.js'
import { SYSTEM_RDD, SYSTEM_SOCKET_ID, RDD_CONFIG, ITEM_TYPES } from "./constants.js"
import { RdDUtility } from "./rdd-utility.js"
import { TMRUtility } from "./tmr-utility.js"
@@ -11,7 +10,6 @@ import { DialogChronologie } from "./dialog-chronologie.js"
import { RdDResolutionTable } from "./rdd-resolution-table.js"
import { RdDTokenHud } from "./rdd-token-hud.js"
import { RdDCommands } from "./rdd-commands.js"
import { RdDCombatManager, RdDCombat } from "./rdd-combat.js"
import { ChatUtility } from "./chat-utility.js"
import { StatusEffects } from "./settings/status-effects.js"
import { RdDCompendiumOrganiser } from "./rdd-compendium-organiser.js"
@@ -39,31 +37,40 @@ import { RdDActorEntiteSheet } from "./actor/entite-sheet.js"
import { RdDActorVehiculeSheet } from "./actor/vehicule-sheet.js"
import { RdDItem } from "./item.js"
import * as models from "./models/_module.mjs"
import * as items from "./documents/_module.mjs"
import * as sheets from "./applications/sheets/_module.mjs"
import { RdDItemArme } from "./item/arme.js"
import { RdDItemArmure } from "./item/armure.js"
import { RdDItemBlessure } from "./item/blessure.js"
import { RdDItemService } from "./item/service.js"
import { RdDItemGemme } from "./item/gemme.js"
import { RdDItemMaladie } from "./item/maladie.js"
import { RdDItemPoison } from "./item/poison.js"
import { RdDItemSigneDraconique } from "./item/signedraconique.js"
import { RdDItemQueue } from "./item/queue.js"
import { RdDItemOmbre } from "./item/ombre.js"
import { RdDItemSort } from "./item-sort.js"
import { RdDItemTete } from "./item/tete.js"
import { RdDItemPoison } from "./item/poison.js"
import { RdDItemPotion } from "./item/potion.js"
import { RdDItemQueue } from "./item/queue.js"
import { RdDItemService } from "./item/service.js"
import { RdDItemRace } from "./item/race.js"
import { RdDItemSigneDraconique } from "./item/signedraconique.js"
import { RdDItemSort } from "./item-sort.js"
import { RdDItemSouffle } from "./item/souffle.js"
import { RdDItemTete } from "./item/tete.js"
import { RdDRencontre } from "./item/rencontre.js"
import { RdDItemSheetV1 } from "./item-sheet.js"
import { RdDBlessureItemSheet } from "./item/sheet-blessure.js"
import { RdDServiceItemSheet } from "./item/sheet-service.js"
import { RdDRencontreItemSheet } from "./item/sheet-rencontre.js"
import { RdDHerbeItemSheet } from "./item/sheet-herbe.js"
import { RdDPlanteItemSheet } from "./item/sheet-plante.js"
import { RdDIngredientItemSheet } from "./item/sheet-ingredient.js"
import { RdDFauneItemSheet } from "./item/sheet-faune.js"
import { RdDConteneurItemSheet } from "./item/sheet-conteneur.js"
import { RdDItemInventaireSheet } from "./item/sheet-base-inventaire.js"
import { RdDGemmeItemSheet } from "./item/sheet-gemme.js"
import { RdDHerbeItemSheet } from "./item/sheet-herbe.js"
import { RdDFauneItemSheet } from "./item/sheet-faune.js"
import { RdDIngredientItemSheet } from "./item/sheet-ingredient.js"
import { RdDInventaireItemSheet } from "./item/sheet-base-inventaire.js"
import { RdDPlanteItemSheet } from "./item/sheet-plante.js"
import { RdDPotionItemSheet } from "./item/sheet-potion.js"
import { RdDRencontreItemSheet } from "./item/sheet-rencontre.js"
import { RdDServiceItemSheet } from "./item/sheet-service.js"
import { RdDSigneDraconiqueItemSheet } from "./item/sheet-signedraconique.js"
import { AppAstrologie } from "./sommeil/app-astrologie.js"
@@ -75,14 +82,10 @@ import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.
import { RdDActorExportSheet } from "./actor/export-scriptarium/actor-encart-sheet.js"
import { RdDStatBlockParser } from "./apps/rdd-import-stats.js"
import { RdDJournalSheet } from "./journal/journal-sheet.js"
import { RdDPotionItemSheet } from "./item/sheet-potion.js"
import { RdDItemPotion } from "./item/potion.js"
import { RdDItemGemme } from "./item/gemme.js"
import { RdDGemmeItemSheet } from "./item/sheet-gemme.js"
import { RdDCombatManager, RdDCombat } from "./rdd-combat.js"
import { Migrations } from './migrations.js'
import * as models from "./models/_module.mjs"
import * as items from "./documents/_module.mjs"
import * as sheets from "./applications/sheets/_module.mjs"
import RollDialog from "./roll/roll-dialog.mjs"
/**
* RdD system
@@ -106,7 +109,7 @@ export class SystemReveDeDragon {
this.itemClasses = {
monnaie: items.RdDItemMonnaie,
munition: items.RdDItemMunition,
tarot: items.RdDModelTarot,
arme: RdDItemArme,
armure: RdDItemArmure,
blessure: RdDItemBlessure,
gemme: RdDItemGemme,
@@ -120,6 +123,7 @@ export class SystemReveDeDragon {
service: RdDItemService,
signedraconique: RdDItemSigneDraconique,
souffle: RdDItemSouffle,
tarot: items.RdDModelTarot,
tete: RdDItemTete,
}
this.actorClasses = {
@@ -206,11 +210,16 @@ export class SystemReveDeDragon {
foundry.documents.collections.Actors.registerSheet(SYSTEM_RDD, RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true })
foundry.documents.collections.Actors.registerSheet(SYSTEM_RDD, RdDActorEntiteSheet, { types: ["entite"], makeDefault: true })
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet)
RdDActorExportSheet.init()
foundry.documents.collections.Items.registerSheet(SYSTEM_RDD, RdDItemInventaireSheet, {
foundry.documents.collections.Items.registerSheet(SYSTEM_RDD, RdDInventaireItemSheet, {
types: [
"objet", "arme", "armure", "livre", "nourritureboisson",
ITEM_TYPES.objet,
ITEM_TYPES.arme,
ITEM_TYPES.armure,
ITEM_TYPES.livre,
ITEM_TYPES.nourritureboisson,
],
makeDefault: true
})
@@ -223,12 +232,31 @@ export class SystemReveDeDragon {
foundry.documents.collections.Items.registerSheet(SYSTEM_RDD, RdDItemSheetV1, {
types: [
"competence", "competencecreature",
"recettealchimique", "musique", "chant", "danse", "jeu", "race",
"recettecuisine", "oeuvre", "meditation",
"queue", "ombre", "souffle", "tete", "casetmr", "sort", "sortreserve",
"nombreastral", "tache", "maladie", "poison", "possession",
"extraitpoetique", "empoignade"
ITEM_TYPES.competence,
ITEM_TYPES.competencecreature,
ITEM_TYPES.recettealchimique,
ITEM_TYPES.musique,
ITEM_TYPES.chant,
ITEM_TYPES.danse,
ITEM_TYPES.jeu,
ITEM_TYPES.race,
ITEM_TYPES.recettecuisine,
ITEM_TYPES.oeuvre,
ITEM_TYPES.meditation,
ITEM_TYPES.queue,
ITEM_TYPES.ombre,
ITEM_TYPES.souffle,
ITEM_TYPES.tete,
ITEM_TYPES.casetmr,
ITEM_TYPES.sort,
ITEM_TYPES.sortreserve,
ITEM_TYPES.nombreastral,
ITEM_TYPES.tache,
ITEM_TYPES.maladie,
ITEM_TYPES.poison,
ITEM_TYPES.possession,
ITEM_TYPES.extraitpoetique,
ITEM_TYPES.empoignade
],
makeDefault: true
})
@@ -263,6 +291,7 @@ export class SystemReveDeDragon {
RdDPossession.init()
TMRRencontres.init()
ExportScriptarium.init()
RollDialog.init()
}
initSettings() {
@@ -346,7 +375,7 @@ export class SystemReveDeDragon {
StatusEffects.onReady()
RdDDice.onReady()
RollDialog.onReady()
RdDStatBlockParser.parseStatBlock()
/* -------------------------------------------- */
/* Affiche/Init le calendrier */
@@ -375,6 +404,10 @@ export class SystemReveDeDragon {
` })
}
}
roll(rollData, actors, options){
RollDialog.create(rollData, actors, options)
}
}
SystemReveDeDragon.start()

View File

@@ -109,7 +109,7 @@ export class RdDResolutionTable {
rolled.caracValue = caracValue;
rolled.finalLevel = finalLevel;
rolled.bonus = rollData.bonus;
rolled.factorHtml = Misc.getFractionHtml(rollData.diviseurSignificative);
rolled.factorHtml = Misc.getFractionOneN(rollData.diviseurSignificative);
if (ReglesOptionnelles.isUsing("afficher-colonnes-reussite")) {
rolled.niveauNecessaire = this.findNiveauNecessaire(caracValue, rolled.roll);

View File

@@ -123,7 +123,7 @@ export class RdDRollResolutionTable extends Dialog {
// Mise à jour valeurs
this.html.find("[name='carac']").val(rollData.caracValue);
this.html.find(".roll-param-resolution").text(rollData.selectedCarac.value + " / " + Misc.toSignedString(rollData.finalLevel));
this.html.find(".roll-part-resolution").text(rollData.selectedCarac.value + " / " + Misc.toSignedString(rollData.finalLevel));
this.html.find("div.placeholder-resolution").empty().append(htmlTable)
}

View File

@@ -5,7 +5,8 @@ export class RdDRollResult {
static async displayRollData(rollData, actor = undefined, template = 'chat-resultat-general.hbs') {
const chatMessage = await ChatUtility.createChatWithRollMode(
{ content: await RdDRollResult.buildRollDataHtml(rollData, template) },
actor
actor,
rollData.current?.rollmode?.key
)
return chatMessage
}

View File

@@ -39,7 +39,7 @@ export class RdDRoll extends Dialog {
difficultesLibres: CONFIG.RDD.difficultesLibres,
etat: actor.getEtatGeneral(),
moral: actor.getMoralTotal(), /* La valeur du moral pour les jets de volonté */
amoureux: actor.listeSuivants(it => it.coeur > 0),
amoureux: actor.listeAmoureux(),
carac: foundry.utils.duplicate(actor.system.carac),
finalLevel: 0,
diffConditions: 0,
@@ -54,7 +54,7 @@ export class RdDRoll extends Dialog {
surenc: actor.isSurenc(),
encTotal: true
},
isMalusEncombrementTotal: RdDItemCompetence.isMalusEncombrementTotal(rollData.competence),
isMalusEncombrementTotal: RdDItemCompetence.isMalusEncombrementTotal(rollData.competence?.name),
encTotal: actor.getEncTotal(),
ajustementAstrologique: actor.ajustementAstrologique(),
surprise: actor.getSurprise(false),
@@ -314,15 +314,15 @@ export class RdDRoll extends Dialog {
rollData.dmg = rollData.attackerRoll?.dmg ?? RdDBonus.dmg(rollData, this.actor)
rollData.caracValue = parseInt(rollData.selectedCarac.value)
rollData.dmg.mortalite = rollData.dmg.mortalite ?? 'mortel';
rollData.use.appelAuMoral = this.actor.isPersonnage() && RdDCarac.isActionPhysique(rollData.selectedCarac);
rollData.use.appelAuMoral = this.actor.isPersonnage() && RdDCarac.isActionPhysique(rollData.selectedCarac?.label);
RollDataAjustements.calcul(rollData, this.actor);
const resolutionTable = await RdDResolutionTable.buildHTMLTable(RdDResolutionTable.subTable(rollData.caracValue, rollData.finalLevel))
const adjustements = await this.buildAjustements(rollData);
HtmlUtility.showControlWhen(this.html.find(".use-encTotal"), rollData.ajustements.encTotal.visible && RdDCarac.isAgiliteOuDerobee(rollData.selectedCarac));
HtmlUtility.showControlWhen(this.html.find(".use-surenc"), rollData.ajustements.surenc.visible && RdDCarac.isActionPhysique(rollData.selectedCarac));
HtmlUtility.showControlWhen(this.html.find(".use-encTotal"), rollData.ajustements.encTotal.visible && RdDCarac.isAgiliteOuDerobee(rollData.selectedCarac?.label));
HtmlUtility.showControlWhen(this.html.find(".use-surenc"), rollData.ajustements.surenc.visible && RdDCarac.isActionPhysique(rollData.selectedCarac?.label));
HtmlUtility.showControlWhen(this.html.find(".use-astrologique"), rollData.ajustements.astrologique.visible);
HtmlUtility.showControlWhen(this.html.find(".utilisation-moral"), rollData.use.appelAuMoral);
HtmlUtility.showControlWhen(this.html.find(".divAppelAuMoral"), rollData.use.appelAuMoral);

View File

@@ -1,7 +1,7 @@
import { SHOW_DICE, SYSTEM_RDD } from "./constants.js";
import { RollDataAjustements } from "./rolldata-ajustements.js";
import { RdDUtility } from "./rdd-utility.js";
import { TMRUtility } from "./tmr-utility.js";
import { COORD_TMR_INCONNU, TMRUtility } from "./tmr-utility.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDTMRRencontreDialog } from "./rdd-tmr-rencontre-dialog.js";
import { ChatUtility } from "./chat-utility.js";
@@ -996,6 +996,10 @@ export class RdDTMRDialog extends Dialog {
const targetOddq = this.pixiTMR.computeEventOddq(event)
const targetCoord = TMRUtility.oddqToCoordTMR(targetOddq)
if (targetCoord == COORD_TMR_INCONNU){
ui.notifications.error("Vous ne pouvez pas vous déplacer ici");
return
}
// Validation de la case de destination (gestion du cas des rencontres qui peuvent téléporter)
const typeDeplacement = this._calculDeplacement(targetCoord, currentCoord, currentOddq, targetOddq);

View File

@@ -1,6 +1,5 @@
/* -------------------------------------------- */
import { HtmlUtility } from "./html-utility.js";
import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js";
import { Targets } from "./targets.js";
@@ -31,11 +30,11 @@ export class RdDTokenHud {
const combatant = game.combat.combatants.find(c => c.tokenId == tokenId)
const actor = RdDCombatManager.getActorCombatant(combatant, { warning: false })
if (actor) {
let actions = RdDCombatManager.listActionsActorCombatant(actor)
const actions = RdDCombatManager.listActionsActorCombatant(actor)
// initiative
await RdDTokenHud.addExtensionHudInit(html, combatant, actions)
// combat
await RdDTokenHud.addExtensionHudCombat(html, combatant, token, actions)
await RdDTokenHud.addExtensionHudCombat(html, combatant, token, actions.filter(it => !it.initOnly))
}
}
@@ -68,18 +67,19 @@ export class RdDTokenHud {
}
static async addExtensionHudCombat(html, combatant, token, actions) {
const hudData = { combatant, token, actions, commandes: [] };
const controlIconTarget = $(html).find('.control-icon[data-action=target]');
await RdDTokenHud._configureSubMenu(controlIconTarget, 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.hbs', hudData,
(event) => {
const actionIndex = event.currentTarget.attributes['data-action-index']?.value;
const action = hudData.actions[actionIndex];
const possession = action.action == 'possession' ? combatant.actor.getPossession(action.system.possessionid) : undefined;
const possession = action.action == 'possession' ? combatant.actor.getPossession(action.possessionid) : undefined;
if (possession) {
combatant.actor.conjurerPossession(possession);
}
else {
combatant.actor.rollArme(action, 'competence', token)
combatant.actor.rollArme(action.arme, action.main, token)
}
});
}
@@ -89,7 +89,7 @@ export class RdDTokenHud {
if (target?.actor) {
const hudSoins = { blessures: target.actor.blessuresASoigner() ?? [] };
if (hudSoins.blessures.length > 0) {
const controlIconTarget = html.find('.control-icon[data-action=combat]');
const controlIconTarget = $(html).find('.control-icon[data-action=combat]');
await RdDTokenHud._configureSubMenu(controlIconTarget,
'systems/foundryvtt-reve-de-dragon/templates/hud-actor-soins.hbs',
hudSoins,

View File

@@ -221,6 +221,7 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/common/compendium-link.hbs',
'systems/foundryvtt-reve-de-dragon/templates/partial-description-overflow.hbs',
'systems/foundryvtt-reve-de-dragon/templates/partial-description-sort.hbs',
'systems/foundryvtt-reve-de-dragon/templates/partial-description.hbs',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.hbs',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-astrologique.hbs',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-coeur.hbs',
@@ -273,7 +274,8 @@ export class RdDUtility {
Handlebars.registerHelper('linkCompendium', (pack, id, name) => RdDUtility.linkCompendium(pack, id, name));
Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionnelles.isUsing(option));
Handlebars.registerHelper('plusMoins', diff => (diff > 0 ? '+' : '') + Math.round(diff))
Handlebars.registerHelper('plusMoins', diff => parseInt(diff) ? (diff > 0 ? '+' : '') + Math.round(diff) : diff)
Handlebars.registerHelper('fractionOneN', n => new Handlebars.SafeString(Misc.getFractionOneN(n)))
// Handle v12 removal of this helper
Handlebars.registerHelper('select', function (selected, options) {
@@ -318,6 +320,7 @@ export class RdDUtility {
// gestion des dates et heures
Handlebars.registerHelper('timestamp-imgSigneHeure', (heure) => { return new Handlebars.SafeString(RdDTimestamp.imgSigneHeure(heure)) });
Handlebars.registerHelper('timestamp-imgSigne', (heure) => { return new Handlebars.SafeString(RdDTimestamp.imgSigne(heure)) });
Handlebars.registerHelper('timestamp-label', (heure) => RdDTimestamp.definition(heure)?.label ?? 'inconnue')
Handlebars.registerHelper('timestamp-definition', (heure) => RdDTimestamp.definition(heure))
Handlebars.registerHelper('timestamp-extract', timestamp => new RdDTimestamp(timestamp).toCalendrier());
Handlebars.registerHelper('timestamp-formulesDuree', () => RdDTimestamp.formulesDuree());
@@ -813,9 +816,8 @@ export class RdDUtility {
static getSelectedToken(actor) {
if (canvas.tokens.controlled.length > 0) {
const tokens = canvas.tokens.controlled
.filter(it => it.actor.id == actor.id)
return tokens[0]
return canvas.tokens.controlled
.find(it => it.actor.id == actor.id)
}
return undefined
}

View File

@@ -0,0 +1,60 @@
import { ActorToken } from "../actor-token.mjs"
export class RollBasicParts {
restore(rollData) {
rollData.ids.sceneId = rollData.ids.sceneId ?? canvas.scene.id
rollData.active = RollBasicParts.$getActor(rollData)
rollData.opponent = RollBasicParts.$getOpponent(rollData)
if (rollData.mode.opposed == undefined) {
rollData.mode.opposed = rollData.opponent != null
}
}
initFrom(rollData) {
return {
selected: {},
mode: {
current: rollData.mode.current
},
ids: {
sceneId: rollData.ids.sceneId,
actorId: rollData.active.id,
actorTokenId: rollData.active.tokenId,
opponentId: rollData.mode.opposed ? rollData.opponent.id : undefined,
opponentTokenId: rollData.mode.opposed ? rollData.opponent.tokenId : undefined,
}
}
}
static $getActor(rollData) {
if (rollData.ids.actorTokenId) {
return ActorToken.fromTokenId(rollData.ids.actorTokenId, rollData.ids.sceneId)
}
else {
const actorId = rollData.ids.actorId ?? (canvas.tokens.controlled.length == 1
/** TODO: jets de plusieurs personnages??? */
? canvas.tokens.controlled[0]
: undefined)
return ActorToken.fromActorId(actorId, () => { throw new Error("Pas d'acteur sélectionné") })
}
}
static $getOpponent(rollData) {
if (rollData.ids.opponentTokenId) {
return ActorToken.fromTokenId(rollData.ids.opponentTokenId, rollData.ids.sceneId)
}
else if (rollData.ids.opponentId) {
return ActorToken.fromActorId(rollData.ids.opponentId)
}
else {
const targets = Array.from(game.user.targets)
if (targets.length == 1) {
return ActorToken.fromToken(targets[0])
}
else {
return undefined
}
}
}
}

View File

@@ -0,0 +1,28 @@
export const ROLL_MODE_ATTAQUE = 'attaque'
export const ROLL_MODE_COMP = 'comp'
export const ROLL_MODE_DEFENSE = 'defense'
export const ROLL_MODE_JEU = 'jeu'
export const ROLL_MODE_MEDITATION = 'meditation'
export const ROLL_MODE_OEUVRE = 'oeuvre'
export const ROLL_MODE_SORT = 'sort'
export const ROLL_MODE_TACHE = 'tache'
export const DIFF_MODE = {
LIBRE: 'libre',
ATTAQUE: 'attaque',
IMPOSEE: 'imposee',
DEFENSE: 'defense',
DEFAUT: 'defaut',
AUCUN: 'aucun'
}
export const DIFF_MODES = {
[DIFF_MODE.LIBRE]: { key: DIFF_MODE.LIBRE, label: "Difficulté libre", libre: true, visible: true, max: 0 },
[DIFF_MODE.ATTAQUE]: { key: DIFF_MODE.ATTAQUE, label: "Difficulté d'attaque", libre: true, visible: true, max: 0 },
[DIFF_MODE.IMPOSEE]: { key: DIFF_MODE.IMPOSEE, label: "Diffficulté imposée", libre: false, visible: true, max: 0 },
[DIFF_MODE.DEFENSE]: { key: DIFF_MODE.DEFENSE, label: "Diffficulté défense", libre: false, visible: true, max: 0 },
[DIFF_MODE.DEFAUT]: { key: DIFF_MODE.DEFAUT, label: "Difficulté", libre: true, visible: true, max: 5 },
[DIFF_MODE.AUCUN]: { key: DIFF_MODE.AUCUN, label: "", libre: false, visible: false, max: 0 },
}

View File

@@ -0,0 +1,90 @@
import { Misc } from "../misc.js";
import { PART_APPELMORAL } from "./roll-part-appelmoral.mjs";
import { PART_COMP } from "./roll-part-comp.mjs";
import { RdDResolutionTable } from "../rdd-resolution-table.js";
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
import { PART_OEUVRE } from "./roll-part-oeuvre.mjs";
/* -------------------------------------------- */
export class RollDialogAdapter {
async rollDice(rollData, rollTitle) {
const chances = this.computeChances({
carac: rollData.current.carac.value,
diff: rollData.current.totaldiff,
bonus: rollData.current.bonus,
sign: rollData.current.sign,
showDice: rollData.options.showDice,
rollMode: rollData.current.rollmode.key
})
const rolled = await this.rollChances(rollData, chances)
this.adjustRollDataForV1(rollData, rolled, rollTitle)
return rolled
}
computeChances({ carac, diff, bonus, sign, showDice, rollMode }) {
const chances = foundry.utils.duplicate(RdDResolutionTable.computeChances(carac, diff))
RdDResolutionTable._updateChancesWithBonus(chances, bonus, diff)
RdDResolutionTable._updateChancesFactor(chances, sign)
chances.showDice = showDice
chances.rollMode = rollMode
return chances
}
async rollChances(rollData, chances) {
const rolled = await RdDResolutionTable.rollChances(chances, rollData.current.sign, rollData.current.resultat)
rolled.caracValue = rollData.current.carac.value
rolled.finalLevel = rollData.current.totaldiff
rolled.bonus = rollData.current.bonus ?? 0
rolled.factorHtml = Misc.getFractionOneN(rollData.current.sign.diviseur)
return rolled
}
adjustRollDataForV1(rollData, rolled, rollTitle) {
// temporaire pour être homogène roll v1
rollData.alias = rollData.active.actor.getAlias()
// pour experience
rollData.finalLevel = rollData.current.totaldiff
if (rollData.use == undefined) { rollData.use = {} }
if (rollData.show == undefined) { rollData.show = {} }
if (rollData.ajustements == undefined) {
rollData.ajustements = {}
}
rollData.selectedCarac = rollData.active.actor.system.carac[rollData.current.carac.key]
const compKey = rollData.current.comp?.key
if (compKey) {
rollData.competence = rollData.refs[PART_COMP].all.find(it => it.key == compKey)?.comp
rollData.jetResistance = rollData.mode.jetResistance
}
const oeuvreKey = rollData.current.oeuvre?.key
if (oeuvreKey) {
const oeuvreCurrent = rollData.current[PART_OEUVRE];
rollData.oeuvre = oeuvreCurrent.oeuvre
// rollData.oeuvre = rollData.refs[PART_OEUVRE].oeuvres.find(it => it.key == oeuvreKey)?.oeuvre
rollData.art = oeuvreCurrent.art.type
}
// pour appel moral
rollData.diviseurSignificative = rollData.current.sign
if (rollData.current[PART_APPELMORAL]?.checked) {
rollData.use.moral = true
}
rollData.rolled = rolled
if (ReglesOptionnelles.isUsing("afficher-colonnes-reussite")) {
rolled.niveauNecessaire = this.findNiveauNecessaire(carac, rolled.roll)
rolled.ajustementNecessaire = rolled.niveauNecessaire - diff
}
rollData.ajustements = rollData.ajustements.map(aj => {
return {
used: true,
label: aj.label,
value: aj.diff,
descr: aj.diff == undefined ? aj.label : undefined
}
})
rollData.show.title = rollTitle
}
}

439
module/roll/roll-dialog.mjs Normal file
View File

@@ -0,0 +1,439 @@
import { Misc } from "../misc.js";
import { RollModeComp } from "./roll-mode-comp.mjs";
import { RollModeTache } from "./roll-mode-tache.mjs";
import { RollModeAttaque } from "./roll-mode-attaque.mjs";
import { RollModeDefense } from "./roll-mode-defense.mjs";
import { RollModeMeditation } from "./roll-mode-meditation.mjs";
import { RollModeSort } from "./roll-mode-sort.mjs";
import { RollModeOeuvre } from "./roll-mode-oeuvre.mjs";
import { RollModeJeu } from "./roll-mode-jeu.mjs";
import { RollPartAction } from "./roll-part-action.mjs";
import { RollPartActor } from "./roll-part-actor.mjs";
import { RollPartAppelMoral } from "./roll-part-appelmoral.mjs";
import { RollPartAstrologique } from "./roll-part-astrologique.mjs";
import { RollPartCarac } from "./roll-part-carac.mjs";
import { RollPartCoeur } from "./roll-part-coeur.mjs";
import { PART_COMP, RollPartComp } from "./roll-part-comp.mjs";
import { RollPartConditions } from "./roll-part-conditions.mjs";
import { RollPartDiff } from "./roll-part-diff.mjs";
import { RollPartEncTotal } from "./roll-part-enctotal.mjs";
import { RollPartEtat } from "./roll-part-etat.mjs";
import { RollPartEthylisme } from "./roll-part-ethylisme.mjs";
import { RollPartMalusArmure } from "./roll-part-malusarmure.mjs";
import { RollPartMeditation } from "./roll-part-meditation.mjs";
import { RollPartMoral } from "./roll-part-moral.mjs";
import { RollPartOpponent } from "./roll-part-opponent.mjs";
import { RollPartSurEnc } from "./roll-part-surenc.mjs";
import { RollPartTricher } from "./roll-part-tricher.mjs";
import { RollPartTache } from "./roll-part-tache.mjs";
import { RollPartOeuvre } from "./roll-part-oeuvre.mjs";
import { RollPartSort } from "./roll-part-sort.mjs";
import { RollBasicParts } from "./roll-basic-parts.mjs";
import { RollPartRollMode } from "./roll-part-rollmode.mjs";
import { RollPartJeu } from "./roll-part-jeu.mjs";
import { RollPartSign } from "./roll-part-sign.mjs";
import { RollPartAttaque } from "./roll-part-attaque.mjs";
import { RollPartDefense } from "./roll-part-defense.mjs";
import { RollDialogAdapter } from "./roll-dialog-adapter.mjs";
import { ROLLDIALOG_SECTION } from "./roll-part.mjs";
import { ROLL_MODE_COMP } from "./roll-constants.mjs";
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api
const doNothing = (dialog) => { }
const ROLL_MODE_TABS = [
new RollModeComp(),
new RollModeTache(),
new RollModeAttaque(),
new RollModeDefense(),
// new RollModeParade??
// new RollModeEsquive??
// new RollModeResistance ??
new RollModeSort(),
new RollModeMeditation(),
new RollModeOeuvre(),
new RollModeJeu(),
]
const BASIC_PARTS = new RollBasicParts()
const ROLL_PARTS = [
new RollPartActor(),
new RollPartAction(),
new RollPartOpponent(),
new RollPartCarac(),
new RollPartComp(),
new RollPartDiff(),
new RollPartAttaque(),
new RollPartDefense(),
new RollPartMeditation(),
new RollPartSort(),
new RollPartTache(),
new RollPartOeuvre(),
new RollPartJeu(),
new RollPartSign(),
new RollPartEtat(),
new RollPartConditions(),
new RollPartEthylisme(),
new RollPartMalusArmure(),
new RollPartEncTotal(),
new RollPartSurEnc(),
new RollPartAppelMoral(),
new RollPartMoral(),
new RollPartCoeur(),
new RollPartAstrologique(),
new RollPartTricher(),
new RollPartRollMode(),
]
/**
* Extend the base Dialog entity to select roll parameters
* @extends {Dialog}
* # Principes
* - une seule fenêtre de dialogue (classe RollDialog)
* - plusieurs modes de fonctionnement (classe RollMode)
* - gestion uniforme des modificateurs (classe RollPart)
* - un objet rollData contient les informations liées à un jet de dés
* - un rollData doit pouvoir être "réduit" pour fournir les informations significatives
* d'un jet de dés
* - un rollData réduit doit pouvoir être complété pour afficher la même fenêtre
* - un rollData réduit sera utilisé pour piloter l'ouverture de la fenêtre
*
* - TODO: une classe de base RollChatMessage gerera les messages correspondant aux résultats du dés
* - TODO: réfléchir aux messages supplémentaires gérés par RdDCombat ?
*
* ## Modes de fonctionnement - RollMode
*
* Un mode de fonctionnement (RollMode) détermine quelles parties (RollPart) de la
* fenêtre RollDialog sont actives, mais aussi quels sont les effets du jet.
*
* - chaque mode de fonctionnement peut impacter les RollPart utilisés, les données
* attendues et ajoutées au rollData.
* - chaque mode de fonctionnement peut définir le template de ChatMessage correspondant
* - Le mode de fonctionnement détermine aussi quelles sont les effets du jet:
* - quelle ChatMessage afficher dans le tchat?
* - en cas d'attaque/de défense, quelles sont les suites à donner?
* - en cas de lancement de sort, réduire les points de rêve
* - en cas de méditation, créer le signe draconique
* - en cas de tâche, ajuster les points de tâche
*
*
* ## Modificateurs - RollPart
* - Chaque modificateur a:
* - un code (comp, carac, diff, ...)
* - une partie dédiée pour sauvegarder son contexte
* - le contexte d'un RollPart est stocké dans le rollData de la fenêtre RollDialog,
* dans des parties dédiés:
* - `rollData.refs[code]` pour les données de référentiel (liste de compétences, ...)
* - `rollData.current[code]` pour les informations d'état courante (la compétence sélectionnée, ...)
* - `rollData.selected[code]` pour les informations à sauvegarder, et utilisées pour paramétrer l'ouverture
* - Chaque RollPart gère ses données dans cet espace dédié.
* - Chaque RollPart a un sous-template dédié, et indique où il doit s'afficher dans le RollDialog
* - Chaque RollPart peut enregistrer ses propres events handlers pour mettre à jour son contexte (et généralement réafficher le RollDialo)
* - Chaque RollPart fournit les informations contextuelles associées au jet
* - TODO: chaque RollPart peut fournir un sous-template pour le ChatMessage correspondant au résultat du dé.
*
* ## boucle de rétroaction
* Lors de l'affichage, chaque RollPart peut fournir un filtre pour les autres RollParts.
* Ce filtre sert principalement à filtrer les caractéristiques/compétense.
*
* Une fois ce filtrage effectué, chaque RollPart va pouvoir modifier sa partie du contexte
* de la fenêtre, permettant à son template hbs d'avoir les donnéers à afficher.
*
* Enfin, lors de l'affichage (vu que les contrêles sont réaffichés), il peut
* enregistrer les listeners appropriés.
*
* ## Utilisation des informations sélectionnées
*
* Le rollData est la structure de stockage, et sert à préparer le jet de dé.
* Le résultat du jet est stocké dans le noeud `rollData.rolled` (comme pour
* la première version de jets de dés)
*
*
* # TODO
* - intégration pour un jet (oeuvres / tâches / méditation / compétence)
* - RdDRollResult V2 (affichage avec templates basés sur roll-dialog)
* - Extraction de jet résumé (pour appel chance)
* - gestion significative
* - Attaque
* - Défense
* - intégration rdd-combat
* - combat rencontres
*
*/
/* -------------------------------------------- */
export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2)
{
static init() {
}
static onReady() {
foundry.applications.handlebars.loadTemplates({
'roll-section': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-section.hbs',
'roll-mode': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-mode.hbs',
'roll-table': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-table.hbs',
'roll-ajustements': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-ajustements.hbs',
'roll-chances': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-chances.hbs',
'roll-button': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-button.hbs',
})
foundry.applications.handlebars.loadTemplates(ROLL_MODE_TABS.map(m => m.template))
foundry.applications.handlebars.loadTemplates(ROLL_PARTS.map(p => p.template))
ROLL_PARTS.forEach(p => p.onReady())
Handlebars.registerHelper('roll-centered-array', (base, show) => RollDialog.centeredArray(base, show))
Handlebars.registerHelper('roll-list-item-value', (list, key, path = undefined) => {
const selected = list.find(p => p.key == key)
if (selected && path && path != '') {
return foundry.utils.getProperty(selected, path)
}
return selected
})
Handlebars.registerHelper('roll-part-context', (rollData, code) => {
const rollPart = ROLL_PARTS.find(it => it.code == code)
if (rollPart == undefined) {
return {}
}
return {
code: code,
name: rollPart.name,
template: rollPart.template,
rollData: rollData,
refs: rollPart.getRefs(rollData),
current: rollPart.getCurrent(rollData)
}
})
}
static centeredArray(base, show) {
show = Math.abs(show)
const start = base - show
return [...Array(2 * show + 1).keys()].map(it => start + it)
}
static async create(rollData, rollOptions = {}) {
const rollDialog = new RollDialog(rollData, rollOptions)
rollDialog.render(true)
}
static get PARTS() {
return { form: { template: 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-dialog.hbs', } }
}
static get DEFAULT_OPTIONS() {
const default_options = {
tag: "form",
form: {
handler: RollDialog.handler,
submitOnChange: false,
closeOnSubmit: false
},
position: {
width: 600,
height: "auto",
},
}
return default_options
}
static async handler(event, form, formData) {
// rien pour l'instant
}
constructor(rollData, rollOptions) {
super()
this.rollData = rollData
// const callbacks = this.rollOptions.callbacks.map(c =>
// r => r.activve.actor Promise.all(this.rollOptions.callbacks.map(async callback => await callback(rollData.active.actor, rollData)))
// )
this.rollOptions = {
callbacks: [
async (actor, r) => await actor.appliquerAjoutExperience(r),
async (actor, r) => await actor.appliquerAppelMoral(r),
...(rollOptions.callbacks ?? [])
],
customChatMessage: rollOptions.customChatMessage,
onRoll: rollOptions.onRoll ?? doNothing
}
this.$loadParts()
}
/** pre-configure les paramètres des différentes parties de la fenêtre (par exemple, prépare les listes de caractéristiques/compétences */
$loadParts() {
const rollData = this.rollData;
const loadedMode = rollData.mode?.current
rollData.current = rollData.current ?? {}
rollData.selected = rollData.selected ?? {}
rollData.mode = rollData.mode ?? {}
rollData.mode.retry = rollData.mode.retry ?? false
BASIC_PARTS.restore(rollData)
rollData.mode.allowed = rollData.mode.retry ? [loadedMode] : rollData.mode.allowed ?? ROLL_MODE_TABS.map(m => m.code)
rollData.mode.current = loadedMode ?? ROLL_MODE_TABS.find(m => m.isAllowed(rollData) && m.visible(rollData))?.code ?? ROLL_MODE_COMP
this.getSelectedMode().setRollDataMode(rollData)
rollData.refs = this.$prepareRefs(rollData)
rollData.options = rollData.options ?? { showDice: true, rollMode: game.settings.get("core", "rollMode") }
ROLL_PARTS.forEach(p => p.initialize(rollData))
ROLL_PARTS.forEach(p => p.restore(rollData))
ROLL_PARTS.filter(p => p.isValid(rollData))
.forEach(p => {
p.loadRefs(rollData)
p.prepareContext(rollData)
})
this.selectMode();
}
selectMode() {
this.rollData.mode.label = this.getSelectedMode().title(this.rollData)
this.getSelectedMode().setRollDataMode(this.rollData)
this.getSelectedMode().onSelect(this.rollData);
}
$prepareRefs(rollData) {
return foundry.utils.mergeObject(rollData.refs ?? {}, Object.fromEntries(ROLL_PARTS.map(p => [p.code, {}])));
}
$saveParts() {
const target = BASIC_PARTS.initFrom(this.rollData)
ROLL_PARTS.filter(p => p.isActive(this.rollData))
.forEach(p => p.store(this.rollData, target))
return target
}
getActiveParts() {
return ROLL_PARTS.filter(p => p.isActive(this.rollData))
}
get title() {
return this.rollData.title ?? `Jet de dés de ${this.rollData.active.actor.name}`
}
async _onRender(context, options) {
this.window.title.innerText = this.rollTitle(this.rollData)
const buttonRoll = this.element.querySelector(`button[name="roll-dialog-button"]`)
buttonRoll?.addEventListener(
"click", e => {
e.preventDefault()
this.roll()
}
)
const buttonsMode = this.element.querySelectorAll(`button[name="roll-mode"]`)
buttonsMode?.forEach(it => it.addEventListener(
"click", e => {
e.preventDefault()
this.rollData.mode.current = e.currentTarget.dataset.mode
this.selectMode()
this.render()
}
))
Promise.all(
this.getActiveParts().map(async p => await p._onRender(this, context, options))
)
}
getAjustements() {
return this.getActiveParts()
.map(p => p.getAjustements(this.rollData))
.reduce((a, b) => a.concat(b))
.sort((a, b) => a.diff == undefined ? 1 : b.diff == undefined ? -1 : 0)
}
async buildHTMLTable(carac, diff) {
return await foundry.applications.handlebars.renderTemplate('roll-table', { carac, diff })
}
async _prepareContext() {
const rollData = this.rollData
const modes = ROLL_MODE_TABS.filter(m => m.isAllowed(rollData) && m.visible(rollData))
.map(m => m.toModeData(rollData))
this.setModeTitle()
const visibleRollParts = this.getActiveParts()
visibleRollParts.forEach(p => p.setExternalFilter(visibleRollParts, rollData))
this.setSpecialComp(visibleRollParts);
visibleRollParts.forEach(p => p.prepareContext(rollData))
this.calculAjustements()
const templates = this.getActiveParts().map(p => p.toTemplateData())
const context = await super._prepareContext()
return foundry.utils.mergeObject(
{
modes: modes,
templates: templates,
rollData: rollData,
}, context)
}
setSpecialComp(visibleRollParts) {
const specialComp = visibleRollParts.map(p => p.getSpecialComp(this.rollData))
.reduce((a, b) => a.concat(b))
if (specialComp.length > 0) {
const rollPartComp = this.getActiveParts()
.find(it => it.code == PART_COMP);
rollPartComp?.setSpecialComp(this.rollData, specialComp)
}
}
calculAjustements() {
this.rollData.ajustements = this.getAjustements()
this.rollData.ajustements.forEach(it => it.isDiff = it.diff != undefined)
this.rollData.current.totaldiff = this.rollData.ajustements
.map(adj => adj.diff)
.filter(d => d != undefined)
.reduce(Misc.sum(), 0)
}
setModeTitle() {
this.rollData.mode.label = this.getSelectedMode()?.title(this.rollData)
}
getSelectedMode() {
return ROLL_MODE_TABS.find(m => m.code == this.rollData.mode.current)
}
async roll() {
this.calculAjustements()
const rollData = this.rollData
console.info('Roll parts:', this.$saveParts())
const rolled = await this.$rollDice(rollData)
rollData.rolled = rolled
Promise.all(this.rollOptions.callbacks.map(async callback => await callback(rollData.active.actor, rollData)))
if (!this.rollOptions.customChatMessage) {
rollData.active.actor.$onRollCompetence(this.rollData)
}
this.rollOptions.onRoll(this)
}
async defaultCallback(rollData, rolled) {
await rollData.active.actor.appliquerAjoutExperience(rollData)
await rollData.active.actor.appliquerAppelMoral(rollData)
}
async $rollDice(rollData) {
const adapter = new RollDialogAdapter(ROLL_PARTS);
return await adapter.rollDice(rollData, this.rollTitle(rollData));
}
rollTitle(rollData) {
return ROLL_PARTS
.filter(it => it.section == ROLLDIALOG_SECTION.ACTION)
.filter(it => it.isActive(rollData))
.map(it => it.title(rollData))
.reduce(Misc.joining(' '))
}
}

View File

@@ -0,0 +1,13 @@
import { DIFF_MODE, ROLL_MODE_ATTAQUE } from "./roll-constants.mjs"
import { RollMode } from "./roll-mode.mjs"
export class RollModeAttaque extends RollMode {
get code() { return ROLL_MODE_ATTAQUE }
get name() { return `Attaquer` }
title(rollData) { return `attaque` }
onSelect(rollData) {
this.setDiffMode(rollData, DIFF_MODE.ATTAQUE)
}
}

View File

@@ -0,0 +1,9 @@
import { ROLL_MODE_COMP } from "./roll-constants.mjs"
import { RollMode } from "./roll-mode.mjs"
export class RollModeComp extends RollMode {
get code() { return ROLL_MODE_COMP }
get name() { return `Jet de caractéristique / compétence` }
title(rollData) { return `fait un jet ${rollData.mode.opposed ? ' contre ' : ''}` }
}

View File

@@ -0,0 +1,17 @@
import { DIFF_MODE, ROLL_MODE_DEFENSE } from "./roll-constants.mjs"
import { RollMode } from "./roll-mode.mjs"
export class RollModeDefense extends RollMode {
get code() { return ROLL_MODE_DEFENSE }
get name() { return `Se défendre` }
title(rollData) { return `se défend${rollData.attacker ? ' de' : ''}` }
getOpponent(rollData) {
return rollData.attacker
}
onSelect(rollData) {
this.setDiffMode(rollData, DIFF_MODE.DEFENSE)
}
}

View File

@@ -0,0 +1,17 @@
import { PART_JEU } from "./roll-part-jeu.mjs"
import { RollMode } from "./roll-mode.mjs"
import { ROLL_MODE_JEU } from "./roll-constants.mjs"
export class RollModeJeu extends RollMode {
get code() { return ROLL_MODE_JEU }
get name() { return `Jouer` }
visible(rollData) { return rollData.active.actor.isPersonnage() }
title(rollData) {
if (rollData.opponent) {
return `joue contre`
}
return `joue: ${rollData.current[PART_JEU].label}`
}
}

View File

@@ -0,0 +1,19 @@
import { DIFF_MODE, ROLL_MODE_MEDITATION } from "./roll-constants.mjs"
import { PART_MEDITATION } from "./roll-part-meditation.mjs"
import { RollMode } from "./roll-mode.mjs"
export class RollModeMeditation extends RollMode {
get code() { return ROLL_MODE_MEDITATION }
get name() { return `Méditation draconique` }
visible(rollData) { return rollData.active.actor.isHautRevant() }
title(rollData) {
const current = rollData.current[PART_MEDITATION]
const theme = current?.meditation.system.theme
return theme ? 'médite sur ' + theme : 'médite'
}
onSelect(rollData) {
this.setDiffMode(rollData, DIFF_MODE.AUCUN)
}
}

View File

@@ -0,0 +1,19 @@
import { DIFF_MODE, ROLL_MODE_OEUVRE } from "./roll-constants.mjs"
import { PART_OEUVRE } from "./roll-part-oeuvre.mjs"
import { RollMode } from "./roll-mode.mjs"
export class RollModeOeuvre extends RollMode {
get code() { return ROLL_MODE_OEUVRE }
get name() { return `Interpréter une oeuvre` }
visible(rollData) { return rollData.active.actor.isPersonnage() }
title(rollData) {
const current = rollData.current[PART_OEUVRE]
return `${current.art.action} ${current.label}`
}
onSelect(rollData) {
this.setDiffMode(rollData, DIFF_MODE.AUCUN)
}
}

View File

@@ -0,0 +1,15 @@
import { DIFF_MODE, ROLL_MODE_SORT } from "./roll-constants.mjs"
import { RollMode } from "./roll-mode.mjs"
import { PART_SORT } from "./roll-part-sort.mjs"
export class RollModeSort extends RollMode {
get code() { return ROLL_MODE_SORT }
get name() { return `lancer un sort` }
visible(rollData) { return rollData.active.actor.isHautRevant() }
title(rollData) { return `lance le sort:` }
onSelect(rollData) {
this.setDiffMode(rollData, DIFF_MODE.AUCUN)
}
}

View File

@@ -0,0 +1,19 @@
import { DIFF_MODE, ROLL_MODE_TACHE } from "./roll-constants.mjs"
import { PART_TACHE } from "./roll-part-tache.mjs"
import { RollMode } from "./roll-mode.mjs"
export class RollModeTache extends RollMode {
get code() { return ROLL_MODE_TACHE }
get name() { return `Travailler à une tâche` }
visible(rollData) { return rollData.active.actor.isPersonnage() }
title(rollData) {
const current = rollData.current[PART_TACHE]
const tache = current?.tache
return `travaille à sa tâche: ${tache.name ?? ''}`
}
onSelect(rollData) {
this.setDiffMode(rollData, DIFF_MODE.AUCUN)
}
}

54
module/roll/roll-mode.mjs Normal file
View File

@@ -0,0 +1,54 @@
import { DIFF_MODE } from "./roll-constants.mjs"
import { PART_DIFF } from "./roll-part-diff.mjs"
const DEFAULT_DIFF_MODES = [DIFF_MODE.LIBRE, DIFF_MODE.IMPOSEE, DIFF_MODE.DEFAUT]
export class RollMode {
onReady() { }
get code() { throw new Error(`Pas de code défini pour ${this}`) }
get name() { return this.code }
get icon() { return `systems/foundryvtt-reve-de-dragon/assets/actions/${this.code}.svg` }
toModeData(rollData) {
return { code: this.code, name: this.name, icon: this.icon, section: 'mode', template: this.template, selected: this.isSelected(rollData) }
}
isAllowed(rollData) { return rollData.mode.allowed == undefined || rollData.mode.allowed.includes(this.code) }
visible(rollData) { return true }
title(rollData) { return this.code }
isSelected(rollData) { return rollData.mode.current == this.code }
setRollDataMode(rollData) {
rollData.mode.opposed = rollData.opponent != undefined
rollData.mode.resistance = false /** TODO */
}
onSelect(rollData) {
const mode = [
rollData.current[PART_DIFF].mode,
this.modeFromOpponents(rollData),
rollData.selected[PART_DIFF].mode].find(m => DEFAULT_DIFF_MODES.includes(m))
this.setDiffMode(rollData, mode ??
DIFF_MODE.DEFAUT)
}
modeFromOpponents(rollData) {
if (rollData.mode.opposed) {
if (rollData.mode.resistance) {
return DIFF_MODE.IMPOSEE
}
return DIFF_MODE.LIBRE
}
return undefined
}
setDiffMode(rollData, mode) {
rollData.current[PART_DIFF].mode = mode
this.setRollDataMode(rollData)
}
}

View File

@@ -0,0 +1,19 @@
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
export const PART_ACTION = "action"
export class RollPartAction extends RollPart {
get code() { return PART_ACTION }
get section() { return ROLLDIALOG_SECTION.ACTION }
title(rollData) {
return rollData.mode.label
}
prepareContext(rollData) {
const current = this.getCurrent(rollData)
current.verb = rollData.mode.label
}
}

View File

@@ -0,0 +1,11 @@
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
export const PART_ACTOR = "actor"
export class RollPartActor extends RollPart {
get code() { return PART_ACTOR }
get section() { return ROLLDIALOG_SECTION.ACTION }
title(rollData) { return rollData.active.name }
}

View File

@@ -0,0 +1,42 @@
import { RdDCarac } from "../rdd-carac.js"
import { RollPartCheckbox } from "./roll-part-checkbox.mjs"
export const PART_APPELMORAL = "appelmoral"
export class RollPartAppelMoral extends RollPartCheckbox {
get code() { return PART_APPELMORAL }
get useCheckboxTemplate() { return false }
get isDefaultChecked() { return false }
visible(rollData) {
return rollData.active.actor.isPersonnage() && RdDCarac.isActionPhysique(rollData.current.carac.key)
}
restore(rollData) {
this.getCurrent(rollData).checked = this.getSaved(rollData).checked ?? false
}
store(rollData, targetData) {
this.setSaved(targetData, { checked: this.getCurrent(rollData).checked })
}
loadRefs(rollData) {
const refs = this.getRefs(rollData)
refs.moral = rollData.active.actor.getMoralTotal()
refs.label = refs.moral > 0 ? "Appel au moral" : "Énergie du désespoir"
}
getCheckboxIcon(rollData) {
const refs = this.getRefs(rollData)
if (refs.moral > 0) {
return '<i class="fa-regular fa-face-smile-beam"></i>'
}
if (refs.moral < 0) {
return '<i class="fa-regular fa-face-sad-tear"></i>'
}
return '<i class="fa-regular fa-face-meh"></i>'
}
getCheckboxLabel(rollData) { return "Appel au moral" }
getCheckboxValue(rollData) { return 1 }
}

View File

@@ -0,0 +1,33 @@
import { Grammar } from "../grammar.js"
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"
import { RollPartCheckbox } from "./roll-part-checkbox.mjs"
export const PART_ASTROLOGIQUE = "astrologique"
export class RollPartAstrologique extends RollPartCheckbox {
get code() { return PART_ASTROLOGIQUE }
get useCheckboxTemplate() { return false }
visible(rollData) {
return this.$isUsingAstrologie() && (
this.isJetChance(rollData)
|| this.isLancementRituel(rollData)
)
}
isLancementRituel(rollData) {
return false
}
isJetChance(rollData) {
return Grammar.includesLowerCaseNoAccent(rollData.current.carac.key, 'chance')
}
$isUsingAstrologie() {
return ReglesOptionnelles.isUsing("astrologie")
}
getCheckboxLabel(rollData) { return "Astrologique" }
getCheckboxValue(rollData) { return rollData.active.actor.ajustementAstrologique() }
}

View File

@@ -0,0 +1,66 @@
import { Grammar } from "../grammar.js"
import { ROLL_MODE_ATTAQUE } 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, RollPart } from "./roll-part.mjs"
export const PART_ATTAQUE = 'attaque'
export class RollPartAttaque extends RollPartSelect {
get code() { return PART_ATTAQUE }
get section() { return ROLLDIALOG_SECTION.CHOIX }
visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_ATTAQUE) }
loadRefs(rollData) {
const refs = this.getRefs(rollData)
const attaques = rollData.active.actor.listAttaques()
refs.attaques = attaques.map(it => RollPartAttaque.$extractAttaque(it, rollData.active.actor))
if (refs.attaques.length>0){
this.$selectAttaque(rollData)
}
}
choices(refs) { return refs.attaques }
static $extractAttaque(action, actor) {
return {
key: `${action.action}::${action.arme.id}::${action.comp.id}`,
label: action.name,
action: action,
arme: action.arme,
comp: action.comp,
}
}
$selectAttaque(rollData, key) {
this.selectByKey(rollData, key, 0)
}
async _onRender(rollDialog, context, options) {
const selectAttaque = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-attaque"]`)
selectAttaque.addEventListener("change", e => {
const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex
this.$selectAttaque(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.setModeTitle()
rollDialog.render()
})
}
getExternalPartsFilter(partCode, rollData) {
if (this.visible(rollData)) {
const current = this.getCurrent(rollData)
switch (partCode) {
case PART_CARAC: return p => Grammar.equalsInsensitive(current.action.carac.key, p.key)
case PART_COMP: return p => p.label == current.comp?.name
}
}
return undefined
}
}

View File

@@ -0,0 +1,66 @@
import { RollPartSelect } from "./roll-part-select.mjs"
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
export const PART_CARAC = "carac"
export class RollPartCarac extends RollPartSelect {
/** TODO: remplacer selectOption par une sorte de sélecteur plus sympa? */
get code() { return PART_CARAC }
get name() { return 'Caractéristiques' }
get section() { return ROLLDIALOG_SECTION.CARAC }
loadRefs(rollData) {
const refs = this.getRefs(rollData)
refs.all = this.$getActorCaracs(rollData)
refs.caracs = refs.all
this.$selectCarac(rollData)
}
choices(refs) { return refs.caracs }
$getActorCaracs(rollData) {
return Object.entries(rollData.active.actor.getCarac())
.filter(([key, c]) => key != 'taille')
/* TODO: filter by context */
.map(([key, carac]) => {
return RollPartCarac.$extractCarac(key, carac)
})
}
static $extractCarac(key, carac) {
return {
key: key,
label: carac.label,
value: parseInt(carac.value)
}
}
setFilter(rollData, filter) {
const refs = this.getRefs(rollData)
refs.caracs = refs.all.filter(filter)
}
prepareContext(rollData) {
this.$selectCarac(rollData)
}
getAjustements(rollData) {
return []
}
async _onRender(rollDialog, context, options) {
const select = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select`)
select?.addEventListener("change", async e => {
const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex
this.$selectCarac(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.render()
})
}
$selectCarac(rollData, key) {
this.selectByKey(rollData, key, 10)
}
}

View File

@@ -0,0 +1,61 @@
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
export class RollPartCheckbox extends RollPart {
get section() { return ROLLDIALOG_SECTION.CONDITIONS }
get useCheckboxTemplate() { return true }
get template() { return this.useCheckboxTemplate ? 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-part-checkbox.hbs' : super.template }
get isDefaultChecked() { return true }
restore(rollData) {
const checked = this.getSaved(rollData).checked
this.getCurrent(rollData).checked = checked == undefined? this.isDefaultChecked : checked
}
store(rollData, targetData) {
this.setSaved(targetData, { checked: this.getCurrent(rollData).checked })
}
loadRefs(rollData) {
const current = this.getCurrent(rollData)
current.label = this.getCheckboxLabel(rollData)
}
prepareContext(rollData) {
const current = this.getCurrent(rollData)
if (current.checked == undefined) {
/* TODO: user setting? */
current.checked = true
}
if (current.value == undefined) {
current.value = this.getCheckboxValue(rollData)
}
current.icon = this.getCheckboxIcon(rollData)
}
getAjustements(rollData) {
const current = this.getCurrent(rollData)
if (current.checked) {
return [{ label: this.getCheckboxLabelAjustement(rollData), diff: current.value }]
}
return []
}
getCheckboxLabelAjustement(rollData) {
return `${this.getCheckboxIcon(rollData)} ${this.getCurrent(rollData).label}`
}
async _onRender(rollDialog, context, options) {
const checkbox = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)
checkbox?.addEventListener("change", e => {
this.getCurrent(rollDialog.rollData).checked = e.currentTarget.checked
rollDialog.render()
})
}
getCheckboxIcon(rollData) { return '' }
getCheckboxLabel(rollData) { return "LABEL" }
getCheckboxValue(rollData) { return 0 }
}

View File

@@ -0,0 +1,66 @@
import { RdDCarac } from "../rdd-carac.js"
import { RollPartSelect } from "./roll-part-select.mjs"
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
const COEUR = "coeur"
const SANS_AMOUR = { key: '', label: "", value: 0 }
export class RollPartCoeur extends RollPartSelect {
get code() { return COEUR }
get section() { return ROLLDIALOG_SECTION.CONDITIONS }
get useCheckboxTemplate() { return false }
isValid(rollData) { return rollData.active.actor.isPersonnage() }
visible(rollData) {
return this.getRefs(rollData).amoureux.length > 1 && RdDCarac.isVolonte(rollData.current.carac.key)
}
loadRefs(rollData) {
const liste = rollData.active.actor.listeAmoureux()
.filter(amour => amour.coeur > 0)
.map(RollPartCoeur.$extractAmoureux)
this.getRefs(rollData).amoureux = [SANS_AMOUR, ...liste]
this.$selectAmoureux(rollData)
}
choices(refs) { return refs.amoureux }
static $extractAmoureux(amour) {
return {
key: amour.id,
label: amour.name,
value: -2 * (amour?.coeur ?? 0),
amour: amour
}
}
$selectAmoureux(rollData, key) {
this.selectByKey(rollData, key, 0)
}
getAjustements(rollData) {
const current = this.getCurrent(rollData)
if (current.key != '') {
return [{
label: "Coeur pour " + current.label,
diff: current.value
}]
}
return []
}
async _onRender(rollDialog, context, options) {
const selectAmour = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="${this.code}"]`)
selectAmour?.addEventListener("change", e => {
const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex
this.$selectAmoureux(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.render()
})
}
}

View File

@@ -0,0 +1,77 @@
import { Grammar } from "../grammar.js"
import { Misc } from "../misc.js"
import { RollPartSelect } from "./roll-part-select.mjs"
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
export const PART_COMP = "comp"
const SANS_COMPETENCE = { key: '', label: "Sans compétence", value: 0 }
export class RollPartComp extends RollPartSelect {
/** TODO: remplacer selectOption par un sélecteur plus sympa (avec image de compétence, par exemple? */
get code() { return PART_COMP }
get name() { return 'Compétences' }
get section() { return ROLLDIALOG_SECTION.COMP }
loadRefs(rollData) {
const refs = this.getRefs(rollData)
refs.all = this.$getActorComps(rollData)
refs.comps = refs.all
this.$selectComp(rollData)
}
choices(refs) { return refs.comps }
$getActorComps(rollData) {
const competences = (rollData.active.actor?.getCompetences() ?? [])
.map(RollPartComp.$extractComp)
.sort(Misc.ascending(it => Grammar.toLowerCaseNoAccentNoSpace(it.label)))
/* TODO: filter competences */
const listCompetences = [
SANS_COMPETENCE,
...competences
]
return listCompetences
}
static $extractComp(comp) {
return {
key: comp.name,
label: comp.name,
value: comp.system.niveau,
comp: comp
}
}
setFilter(rollData, filter) {
const refs = this.getRefs(rollData)
refs.comps = refs.all.filter(filter)
}
prepareContext(rollData) {
this.$selectComp(rollData)
}
setSpecialComp(rollData, comps) {
this.getRefs(rollData).comps = comps.map(RollPartComp.$extractComp)
.sort(Misc.ascending(it => Grammar.toLowerCaseNoAccentNoSpace(it.label)))
}
async _onRender(rollDialog, context, options) {
const select = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select`)
select?.addEventListener("change", e => {
const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex
this.$selectComp(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.render()
})
}
$selectComp(rollData, key) {
this.selectByKey(rollData, key, 0)
}
}

View File

@@ -0,0 +1,74 @@
import { SYSTEM_RDD } from "../constants.js";
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs";
const CONDITIONS = "conditions"
const DESCR_CONDITIONS = "Conditions"
export class RollPartConditions extends RollPart {
/** TODO: use alternate to numberInput that supports displaying '+' sign */
settingMin() { return RollPart.settingKey(this, 'min') }
settingMax() { return RollPart.settingKey(this, 'max') }
onReady() {
game.settings.register(SYSTEM_RDD, this.settingMin(),
{
name: "Malus maximal de conditions",
type: Number,
config: true,
scope: "world",
range: { min: -20, max: -10, step: 1 },
default: -16
}
)
game.settings.register(SYSTEM_RDD, this.settingMax(),
{
name: "Bonus maximal de conditions",
type: Number,
config: true,
scope: "world",
range: { min: 5, max: 15, step: 1 },
default: 10
}
)
}
restore(rollData) {
const current = this.getCurrent(rollData)
current.value = this.getSaved(rollData)?.value ?? current.value ?? 0
}
store(rollData, targetData) {
this.setSaved(targetData, { value: this.getCurrent(rollData).value })
}
/** @override */
get code() { return CONDITIONS }
get section() { return ROLLDIALOG_SECTION.CONDITIONS }
prepareContext(rollData) {
const current = this.getCurrent(rollData)
current.min = game.settings.get(SYSTEM_RDD, this.settingMin())
current.max = game.settings.get(SYSTEM_RDD, this.settingMax())
current.value = current.value ?? 0
}
getAjustements(rollData) {
const current = this.getCurrent(rollData)
if (current.value != 0) {
return [{ label: DESCR_CONDITIONS, diff: current.value }]
}
return []
}
async _onRender(rollDialog, context, options) {
const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)
input?.addEventListener("change", e => {
const current = this.getCurrent(rollDialog.rollData)
current.value = parseInt(e.currentTarget.value)
rollDialog.render()
})
}
}

View File

@@ -0,0 +1,17 @@
import { ROLL_MODE_DEFENSE } from "./roll-constants.mjs"
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
export const PART_DEFENSE = 'defense'
export class RollPartDefense extends RollPart {
get code() { return PART_DEFENSE }
get section() { return ROLLDIALOG_SECTION.CHOIX }
visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_DEFENSE) }
loadRefs(rollData) {
const refs = this.getRefs(rollData)
refs.defenses =[]
}
}

View File

@@ -0,0 +1,70 @@
import { DIFF_MODE, DIFF_MODES, ROLL_MODE_MEDITATION, ROLL_MODE_OEUVRE, ROLL_MODE_SORT, ROLL_MODE_TACHE } from "./roll-constants.mjs";
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs";
export const PART_DIFF = "diff"
const EXCLUDED_ROLL_MODES = [ROLL_MODE_TACHE, ROLL_MODE_MEDITATION, ROLL_MODE_SORT, ROLL_MODE_OEUVRE]
export class RollPartDiff extends RollPart {
get code() { return PART_DIFF }
get section() { return ROLLDIALOG_SECTION.CHOIX }
restore(rollData) {
const current = this.getCurrent(rollData)
const saved = this.getSaved(rollData)
current.value = saved?.value ?? current.value ?? 0
current.mode = saved?.mode ?? current.mode
}
store(rollData, targetData) {
const current = this.getCurrent(rollData)
this.setSaved(targetData, {
value: current.value,
mode: current.mode
})
}
visible(rollData) {
if (EXCLUDED_ROLL_MODES.includes(rollData.mode.current)) {
return false
}
const current = this.getCurrent(rollData)
/* TODO: affiner les cas où afficher ou non. devrait s'afficher pour les jets basiques (même si pas d'opposant sélectionné)*/
return Object.values(DIFF_MODE).includes(current.mode)
}
prepareContext(rollData) {
const current = this.getCurrent(rollData)
const diffMode = DIFF_MODES[current.mode] ?? DIFF_MODES[DIFF_MODE.AUCUN]
foundry.utils.mergeObject(current,
{
mode: diffMode.key,
label: diffMode?.label ?? '',
value: current.value ?? 0,
disabled: !diffMode.libre,
min: -10,
max: diffMode.max
},
{ inplace: true }
)
}
getAjustements(rollData) {
const current = this.getCurrent(rollData)
return [{
label: current.label,
diff: current.value
}]
}
async _onRender(rollDialog, context, options) {
const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)
input?.addEventListener("change", e => {
this.getCurrent(rollDialog.rollData).value = parseInt(e.currentTarget.value)
rollDialog.render()
})
}
}

View File

@@ -0,0 +1,31 @@
import { RdDItemCompetence } from "../item-competence.js"
import { RdDCarac } from "../rdd-carac.js"
import { RollPartCheckbox } from "./roll-part-checkbox.mjs"
const ENCTOTAL = "enctotal"
export class RollPartEncTotal extends RollPartCheckbox {
get code() { return ENCTOTAL }
get useCheckboxTemplate() { return false }
visible(rollData) {
return RdDCarac.isAgiliteOuDerobee(rollData.current.carac.key)
&& RdDItemCompetence.isMalusEncombrementTotal(rollData.current.comp?.key)
}
async _onRender(rollDialog, context, options) {
super._onRender(rollDialog, context, options)
const inputMalusEnc = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="malusenc"]`)
inputMalusEnc?.addEventListener("change", e => {
this.getCurrent(rollDialog.rollData).value = parseInt(e.currentTarget.value)
rollDialog.render()
})
}
getCheckboxIcon(rollData) { return '<i class="fa-solid fa-weight-hanging"></i>' }
getCheckboxLabel(rollData) { return "Enc. total" }
getCheckboxValue(rollData) { return - rollData.active.actor.getEncTotal() }
}

View File

@@ -0,0 +1,30 @@
import { RdDCarac } from "../rdd-carac.js"
import { RollPartCheckbox } from "./roll-part-checkbox.mjs"
const ETAT = "etat"
export class RollPartEtat extends RollPartCheckbox {
get code() { return ETAT }
visible(rollData) {
const selectedCarac = rollData.current.carac?.key ?? ''
if (selectedCarac == '') {
return false
}
if (RdDCarac.isChance(selectedCarac)) {
return false
}
if (RdDCarac.isReve(selectedCarac)) {
if ((rollData.current.comp?.key ?? '') == '') {
return false
}
}
return this.getCheckboxValue(rollData) != 0
}
getCheckboxLabel(rollData) { return "État général" }
getCheckboxValue(rollData) {
return rollData.active.actor.getEtatGeneral({ ethylisme: true })
}
}

View File

@@ -0,0 +1,28 @@
import { RdDCarac } from "../rdd-carac.js"
import { RdDUtility } from "../rdd-utility.js"
import { RollPartCheckbox } from "./roll-part-checkbox.mjs"
const ETHYLISME = "ethylisme"
export class RollPartEthylisme extends RollPartCheckbox {
get code() { return ETHYLISME }
isValid(rollData) { return rollData.active.actor.isPersonnage()}
visible(rollData) {
return rollData.active.actor.isAlcoolise() && !RdDCarac.isChance(rollData.current.carac.key)
}
getCheckboxIcon(rollData) {
return '<i class="fa-solid fa-champagne-glasses"></i>'
}
getCheckboxLabel(rollData) {
return `${RdDUtility.getNomEthylisme(rollData.active.actor.ethylisme())}`
}
getCheckboxValue(rollData) {
return rollData.active.actor.malusEthylisme()
}
}

View File

@@ -0,0 +1,110 @@
import { Grammar } from "../grammar.js"
import { ITEM_TYPES } from "../constants.js"
import { CARACS } from "../rdd-carac.js"
import { ROLL_MODE_JEU } 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"
export const PART_JEU = "jeu"
const COMPETENCE_JEU = 'Jeu'
export class RollPartJeu extends RollPartSelect {
get code() { return PART_JEU }
get section() { return ROLLDIALOG_SECTION.CHOIX }
isValid(rollData) { return rollData.active.actor.isPersonnage() }
visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_JEU) }
loadRefs(rollData) {
const refs = this.getRefs(rollData)
refs.jeux = rollData.active.actor.itemTypes[ITEM_TYPES.jeu]
.map(it => RollPartJeu.$extractJeu(it, rollData.active.actor))
if (refs.jeux.length > 0) {
this.$selectJeu(rollData)
}
}
choices(refs) { return refs.jeux }
static $extractJeu(jeu, actor) {
const comp = actor.getCompetence(COMPETENCE_JEU)
const caracs = jeu.system.caraccomp.toLowerCase().split(/[.,:\/-]/).map(it => it.trim())
const base = RollPartJeu.$getJeuBase(jeu, comp, caracs)
return {
key: jeu.id,
label: jeu.name,
caracs: caracs,
jeu: jeu,
value: (base ?? comp).system.niveau,
base: base,
comp: comp
}
}
static $getJeuBase(jeu, comp, caracs) {
if (jeu.system.base < comp.system.niveau) {
return undefined
}
return {
id: comp.id,
name: `Jeu ${jeu.name}`,
type: comp.type,
img: comp.img,
system: foundry.utils.mergeObject(
{
niveau: jeu.system.base,
base: jeu.system.base,
default_carac: caracs.length > 0 ? caracs[0] : CARACS.CHANCE
},
comp.system,
{ inplace: true, overwrite: false }
)
}
}
prepareContext(rollData) {
const current = this.getCurrent(rollData)
if (rollData.mode.current == ROLL_MODE_JEU && current) {
rollData.mode.opposed = true
}
}
getAjustements(rollData) { return [] }
$selectJeu(rollData, key) {
this.selectByKey(rollData, key, 0)
}
async _onRender(rollDialog, context, options) {
const selectjeu = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-jeu"]`)
selectjeu.addEventListener("change", e => {
const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex
this.$selectJeu(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.setModeTitle()
rollDialog.render()
})
}
getExternalPartsFilter(partCode, rollData) {
if (this.visible(rollData)) {
const current = this.getCurrent(rollData)
switch (partCode) {
case PART_CARAC: return p => current.caracs?.includes(Grammar.toLowerCaseNoAccent(p.key))
case PART_COMP: return p => p.label == current.comp?.name
}
}
return undefined
}
getSpecialComp(rollData) {
const current = this.getCurrent(rollData)
return current.base ? [current.base] : []
}
}

View File

@@ -0,0 +1,16 @@
import { RdDCarac } from "../rdd-carac.js"
import { RollPartCheckbox } from "./roll-part-checkbox.mjs"
const MALUSARMURE = "malusarmure"
export class RollPartMalusArmure extends RollPartCheckbox {
get code() { return MALUSARMURE }
visible(rollData) {
return RdDCarac.isAgiliteOuDerobee(rollData.current.carac.key) && this.getCheckboxValue(rollData) != 0
}
getCheckboxLabel(rollData) { return "Malus armure" }
getCheckboxValue(rollData) { return rollData.active.actor.getMalusArmure() }
}

View File

@@ -0,0 +1,117 @@
import { ITEM_TYPES } from "../constants.js"
import { Grammar } from "../grammar.js"
import { RdDCarac } from "../rdd-carac.js"
import { RdDTimestamp } from "../time/rdd-timestamp.js"
import { TMRUtility } from "../tmr-utility.js"
import { ROLL_MODE_MEDITATION } 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"
export const PART_MEDITATION = "meditation"
export class RollPartMeditation extends RollPartSelect {
get code() { return PART_MEDITATION }
get section() { return ROLLDIALOG_SECTION.CHOIX }
isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() }
visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_MEDITATION) }
loadRefs(rollData) {
const refs = this.getRefs(rollData)
foundry.utils.mergeObject(refs,
{
meditations: rollData.active.actor.itemTypes[ITEM_TYPES.meditation]
.map(it => RollPartMeditation.$extractMeditation(it, rollData.active.actor))
}
)
if (refs.meditations.length > 0) {
this.$selectMeditation(rollData)
}
}
choices(refs) { return refs.meditations }
static $extractMeditation(meditation, actor) {
return {
key: meditation.id,
label: meditation.name,
meditation: meditation,
comp: actor.getCompetence(meditation.system.competence)
}
}
prepareContext(rollData) {
this.getCurrent(rollData).value = this.getMalusConditions(rollData)
}
getMalusConditions(rollData) {
const current = this.getCurrent(rollData)
const conditionsManquantes = [
current.isComportement,
current.isHeure,
current.isPurification,
current.isVeture
].filter(it => !it).length
return -2 * conditionsManquantes
}
getMalusEchecs(rollData) {
return this.getCurrent(rollData).meditation.system.malus
}
getAjustements(rollData) {
const malusEchecs = { label: "Méditation", diff: this.getMalusEchecs(rollData) }
const malusConditions = { label: "Conditions", diff: this.getMalusConditions(rollData) }
return [malusConditions, ...(malusEchecs.diff == 0 ? [] : [malusEchecs])]
}
$selectMeditation(rollData, key) {
const previous = this.getCurrent(rollData)
const current = this.selectByKey(rollData, key, 0)
if (current.key != previous.key) {
const heureMonde = RdDTimestamp.getWorldTime().heure
const heureMeditation = RdDTimestamp.findHeure(current.meditation.system.heure)?.heure
current.isHeure = heureMeditation == heureMonde
current.isTMR = Grammar.equalsInsensitive(current.meditation.system.tmr, TMRUtility.getTMRType(rollData.active.actor.system.reve.tmrpos.coord))
}
}
async _onRender(rollDialog, context, options) {
const selectMeditation = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-meditation"]`)
selectMeditation.addEventListener("change", e => {
const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex
this.$selectMeditation(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.render()
rollDialog.setModeTitle()
})
this.setupListenerCondition(rollDialog, 'isComportement')
this.setupListenerCondition(rollDialog, 'isHeure')
this.setupListenerCondition(rollDialog, 'isPurification')
this.setupListenerCondition(rollDialog, 'isVeture')
}
setupListenerCondition(rollDialog, inputName) {
const checkbox = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${inputName}"]`)
checkbox.addEventListener("change", e => {
const current = this.getCurrent(rollDialog.rollData)
current[inputName] = e.currentTarget.checked
rollDialog.render()
})
}
getExternalPartsFilter(partCode, rollData) {
if (this.visible(rollData)) {
const current = this.getCurrent(rollData)
switch (partCode) {
case PART_CARAC: return p => RdDCarac.isIntellect(p.key)
case PART_COMP: return p => p.label == current.comp?.name
}
}
return undefined
}
}

View File

@@ -0,0 +1,16 @@
import { RdDCarac } from "../rdd-carac.js"
import { RollPartCheckbox } from "./roll-part-checkbox.mjs"
const MORAL = "moral"
export class RollPartMoral extends RollPartCheckbox {
get code() { return MORAL }
visible(rollData) {
return RdDCarac.isVolonte(rollData.current.carac.key) && this.getCheckboxValue(rollData) != 0
}
getCheckboxLabel(rollData) { return "Moral" }
getCheckboxValue(rollData) { return rollData.active.actor.getMoralTotal() }
}

View File

@@ -0,0 +1,99 @@
import { ITEM_TYPES } from "../constants.js"
import { Grammar } from "../grammar.js"
import { Misc } from "../misc.js"
import { CARACS } from "../rdd-carac.js"
import { ROLL_MODE_OEUVRE } 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"
export const PART_OEUVRE = "oeuvre"
const ARTS = [
{ type: ITEM_TYPES.oeuvre, action: "interpréte l'oeuvre", competence: it => it.system.competence, caracs: it => [it.system.default_carac] },
{ type: ITEM_TYPES.chant, action: "chante", competence: it => 'Chant', caracs: it => [CARACS.OUIE] },
{
type: ITEM_TYPES.danse, action: "danse:", competence: it => 'Danse', caracs: it => {
const caracs = []
if (it.system.agilite) { caracs.push(CARACS.AGILITE) }
if (it.system.apparence) { caracs.push(CARACS.APPARENCE) }
return caracs
}
},
{ type: ITEM_TYPES.musique, action: "joue le morceau:", competence: it => 'Musique', caracs: it => [CARACS.OUIE] },
{ type: ITEM_TYPES.recettecuisine, action: "cuisine le plat:", competence: it => 'Cuisine', caracs: it => [CARACS.ODORATGOUT] },
]
export class RollPartOeuvre extends RollPartSelect {
onReady() {
ARTS.forEach(art => art.label = Misc.typeName('Item', art.type))
ARTS.map(it => `roll-oeuvre-${it.type}`)
.forEach(art =>
foundry.applications.handlebars.loadTemplates({ [art]: `systems/foundryvtt-reve-de-dragon/templates/roll/${art}.hbs` })
)
}
get code() { return PART_OEUVRE }
get section() { return ROLLDIALOG_SECTION.CHOIX }
isValid(rollData) { return rollData.active.actor.isPersonnage() }
visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_OEUVRE) }
loadRefs(rollData) {
const refs = this.getRefs(rollData)
refs.oeuvres = rollData.active.actor.items
.filter(it => it.isOeuvre() && RollPartOeuvre.getArt(it))
.map(it => RollPartOeuvre.$extractOeuvre(it, rollData.active.actor))
if (refs.oeuvres.length > 0) {
this.$selectOeuvre(rollData)
}
}
choices(refs) { return refs.oeuvres }
static $extractOeuvre(oeuvre, actor) {
const art = RollPartOeuvre.getArt(oeuvre)
return {
key: oeuvre.id,
label: oeuvre.name,
art: art,
caracs: art.caracs(oeuvre),
value: -oeuvre.system.niveau,
oeuvre: oeuvre,
comp: actor.getCompetence(art.competence(oeuvre))
}
}
static getArt(oeuvre) {
return ARTS.find(it => it.type == oeuvre.type)
}
$selectOeuvre(rollData, key) {
this.selectByKey(rollData, key, 0)
}
async _onRender(rollDialog, context, options) {
const selectOeuvre = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-oeuvre"]`)
selectOeuvre.addEventListener("change", e => {
const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex
this.$selectOeuvre(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.setModeTitle()
rollDialog.render()
})
}
getExternalPartsFilter(partCode, rollData) {
if (this.visible(rollData)) {
const current = this.getCurrent(rollData)
switch (partCode) {
case PART_CARAC: return p => current.caracs?.includes(Grammar.toLowerCaseNoAccent(p.key))
case PART_COMP: return p => p.label == current.comp?.name
}
}
return undefined
}
}

View File

@@ -0,0 +1,12 @@
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
const OPPONENT = "opponent"
export class RollPartOpponent extends RollPart {
get code() { return OPPONENT }
get section() { return ROLLDIALOG_SECTION.ACTION }
visible(rollData) { return rollData.mode.opposed }
title(rollData) { return rollData.opponent?.name ?? '' }
}

View File

@@ -0,0 +1,32 @@
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
const ROLLMODE = "rollmode"
export class RollPartRollMode extends RollPart {
get code() { return ROLLMODE }
get section() { return ROLLDIALOG_SECTION.CONDITIONS }
loadRefs(rollData) {
const refs = this.getRefs(rollData)
refs.rollmodes = Object.entries(CONFIG.Dice.rollModes).map(([k, v]) => { return { key: k, label: v.label, icon: v.icon } })
}
restore(rollData) {
this.setCurrent(rollData, { key: this.getSaved(rollData)?.key ?? game.settings.get("core", "rollMode") })
}
store(rollData, targetData) {
this.setSaved(targetData, { key: this.getCurrent(rollData).key })
}
async _onRender(rollDialog, context, options) {
const rollvisibilityButtons = rollDialog.element.querySelectorAll(`button[name="roll-rollmode"]`)
rollvisibilityButtons?.forEach(it => it.addEventListener(
"click", e => {
e.preventDefault()
this.getCurrent(rollDialog.rollData).key = e.currentTarget.dataset.key
rollDialog.render()
}))
}
}

View File

@@ -0,0 +1,50 @@
import { Grammar } from "../grammar.js"
import { RollPart } from "./roll-part.mjs"
export class RollPartSelect extends RollPart {
restore(rollData) {
this.setCurrent(rollData, { key: this.getSaved(rollData)?.key })
}
store(rollData, targetData) {
this.setSaved(targetData, { key: this.getCurrent(rollData).key })
}
choices(refs) { return [] }
getAjustements(rollData) {
const current = this.getCurrent(rollData)
if (current) {
return [{ label: current.label, diff: current.value }]
}
return []
}
selectByKey(rollData, key = undefined, defValue = undefined) {
const refs = this.getRefs(rollData)
const choices = this.choices(refs) ??[]
const current = this.getCurrent(rollData)
const newChoice = (choices.length == 0)
? { key: '', value: defValue }
: this.$getSelectedChoice(choices, key ?? current?.key ?? refs.key ?? '')
this.setCurrent(rollData, newChoice)
return newChoice
}
$getSelectedChoice(choices, key) {
const potential = choices.filter(it => Grammar.includesLowerCaseNoAccent(it.key, key))
switch (potential.length) {
case 0:
// ui.notifications.warn(`Aucun choix de ${this.name} pour ${key}`)
return choices[0]
case 1:
return potential[0]
default:
const selected = potential.find(it => Grammar.equalsInsensitive(it.key, key))
// ui.notifications.info(`Plusieurs choix de ${this.name} pour ${key}, le premier est utilisé`)
return selected ?? potential[0]
}
}
}

View File

@@ -0,0 +1,93 @@
import { Misc } from "../misc.js"
import { StatusEffects } from "../settings/status-effects.js"
import { ROLL_MODE_ATTAQUE, ROLL_MODE_DEFENSE } from "./roll-constants.mjs"
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
export const PART_SIGN = "sign"
export class RollPartSign extends RollPart {
get code() { return PART_SIGN }
get section() { return ROLLDIALOG_SECTION.AJUSTEMENTS }
loadRefs(rollData) {
this.setFromState(rollData)
}
restore(rollData) {
this.setCurrent(rollData, this.getSaved(rollData))
}
store(rollData, targetData) {
this.setSaved(targetData, this.getCurrent(rollData))
}
// visible(rollData) {
// const current = this.getCurrent(rollData)
// return current.surprise != ''
// }
isCombat(rollData) {
return [ROLL_MODE_ATTAQUE, ROLL_MODE_DEFENSE].includes(rollData.mode.current) || rollData.mode.isCombat
}
prepareContext(rollData) {
this.setFromState(rollData)
}
setFromState(rollData) {
if (rollData.mode.retry) {
return
}
const actor = rollData.active.actor;
const isCombat = this.isCombat(rollData)
const current = this.getCurrent(rollData)
current.surprise = actor.getSurprise(isCombat)
current.reasons = actor.getEffects(it => StatusEffects.niveauSurprise(it) > 0).map(it => it.name)
current.diviseur = 1
if (isCombat && actor.isDemiReve()) {
current.reasons.push('Demi-rêve en combat')
}
if (current.surprise == 'demi') {
current.diviseur *= 2
}
if (this.isAttaqueFinesse(rollData)) {
current.diviseur *= 2
current.reasons.push('Attaque en finesse')
}
if (this.isForceInsuffisante(rollData)) {
current.diviseur *= 2
current.reasons.push('Force insuffisante')
}
current.reason = current.reasons.join(', ')
}
isForceInsuffisante(rollData) {
//this.isCombat(rollData) && ... arme avec force min
return this.isCombat(rollData) && true
}
isAttaqueFinesse(rollData) {
// this.rollData.selected[PART_DEFENSE] && attaquant avec particulière en finesse
return ROLL_MODE_DEFENSE == rollData.mode.current && true
}
getAjustements(rollData) {
const current = this.getCurrent(rollData)
if (current.surprise == 'demi') {
return [{ label: 'Significative requise ' + Misc.getFractionOneN(current.diviseur), diff: undefined }]
}
return []
}
async _onRender(rollDialog, context, options) {
const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)
input?.addEventListener("change", e => {
this.getCurrent(rollDialog.rollData).value = parseInt(e.currentTarget.value)
rollDialog.render()
})
}
}

View File

@@ -0,0 +1,129 @@
import { ITEM_TYPES } from "../constants.js"
import { ROLL_MODE_SORT } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP } from "./roll-part-comp.mjs"
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
import { TMRUtility } from "../tmr-utility.js"
import { RdDItemSort } from "../item-sort.js"
import { RollPartSelect } from "./roll-part-select.mjs"
export const PART_SORT = "sort"
export class RollPartSort extends RollPartSelect {
onReady() {
// TODO: utiliser un hook pour écouter les déplacements dans les TMRs?
}
get code() { return PART_SORT }
get section() { return ROLLDIALOG_SECTION.CHOIX }
isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() }
visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_SORT) }
loadRefs(rollData) {
const refs = this.getRefs(rollData)
const coord = rollData.active.actor.system.reve.tmrpos.coord
const draconics = rollData.active.actor.getDraconicList()
const sorts = rollData.active.actor.itemTypes[ITEM_TYPES.sort]
.map(s => RollPartSort.$extractSort(s, coord, draconics))
foundry.utils.mergeObject(refs,
{
coord: coord,
tmr: TMRUtility.getTMR(coord),
reve: rollData.active.actor.system.reve.reve.value,
draconics: draconics,
all: sorts,
sorts: sorts.filter(it => RdDItemSort.isSortOnCoord(it.sort, coord))
},
{ inplace: true }
)
if (refs.sorts.length > 0) {
this.$selectSort(rollData)
}
}
choices(refs) { return refs.sorts }
static $extractSort(sort, coord, draconics) {
const isDiffVariable = RdDItemSort.isDifficulteVariable(sort)
const isReveVariable = RdDItemSort.isCoutVariable(sort)
return {
key: sort.id,
label: sort.name,
value: isDiffVariable ? -7 : parseInt(sort.system.difficulte),
ptreve: isReveVariable ? 1 : sort.system.ptreve,
caseTMR: RdDItemSort.getCaseTMR(sort),
isDiffVariable: isDiffVariable,
isReveVariable: isReveVariable,
isReserve: false,
sort: sort,
draconics: RdDItemSort.getDraconicsSort(draconics, sort).map(it => it.name)
}
}
getAjustements(rollData) {
const current = this.getCurrent(rollData)
if (current) {
const reserve = current.isReserve ?
[{ label: `Mise en réserve en ${current.coord}` }] : []
const bonusCase = current.bonusCase ?
[{ label: `Bonus case +${current.bonusCase}%` }] : []
return [
{ label: current.label, diff: current.value },
{ label: `r${current.ptreve}` },
...bonusCase,
...reserve
]
}
return []
}
$selectSort(rollData, key) {
const previous = this.getCurrent(rollData)
const current = this.selectByKey(rollData, key, -7)
if (current.key != previous.key) { }
current.bonusCase = RdDItemSort.getCaseBonus(current.sort,
rollData.active.actor.system.reve.tmrpos.coord)
}
async _onRender(rollDialog, context, options) {
const current = this.getCurrent(rollDialog.rollData)
const selectSort = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-sort"]`)
const inputDiff = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="diff-var"]`)
const inputPtReve = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="ptreve-var"]`)
const checkboxReserve = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="reserve"]`)
selectSort.addEventListener("change", e => {
const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex
this.$selectSort(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.setModeTitle()
rollDialog.render()
})
inputDiff?.addEventListener("change", e => {
current.value = parseInt(e.currentTarget.value)
rollDialog.render()
})
inputPtReve?.addEventListener("change", e => {
current.ptreve = parseInt(e.currentTarget.value)
rollDialog.render()
})
checkboxReserve?.addEventListener("change", e => {
current.isReserve = e.currentTarget.checked
rollDialog.render()
})
}
getExternalPartsFilter(partCode, rollData) {
if (this.visible(rollData)) {
const current = this.getCurrent(rollData)
switch (partCode) {
case PART_CARAC: return p => p.key == 'reve'
case PART_COMP: return p => current.draconics?.includes(p.label)
}
}
return undefined
}
}

View File

@@ -0,0 +1,16 @@
import { RdDCarac } from "../rdd-carac.js"
import { RollPartCheckbox } from "./roll-part-checkbox.mjs"
const SURENC = "surenc"
export class RollPartSurEnc extends RollPartCheckbox {
get code() { return SURENC }
visible(rollData) {
return RdDCarac.isActionPhysique(rollData.current.carac.key) && rollData.active.actor.isSurenc()
}
getCheckboxIcon(rollData) { return '<i class="fa-solid fa-weight-hanging"></i>' }
getCheckboxLabel(rollData) { return "Sur-enc." }
getCheckboxValue(rollData) { return rollData.active.actor.computeMalusSurEncombrement() }
}

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