Compare commits

..

1 Commits

Author SHA1 Message Date
eeba257741 Nouveau roll-dialog: mode attaque 2025-09-21 13:44:51 +02:00
194 changed files with 1810 additions and 4779 deletions

View File

@@ -12,8 +12,8 @@ Pseudo : LeRatierBretonnien
Mainteneur/Développeur : LeRatierBretonnien
Développeur : VincentVk
Tests, Compendiums, Données: Fred, Fab, Grendel, LeRatierBretonnien, VincentVk
Styles/CSS : Mandar, VincentVk
Tests, Compendiums, Données: Fred, Fab, Grendel
Styles/CSS : Mandar
# Mentions Légales
@@ -23,6 +23,6 @@ La carte des Terres Médianes du Rêve est une illustration de **Jidus**, utilis
Les silhouettes des créatures, humanoïdes et entités sont des illustrations de **Roland Barthélémy**, et sont utilisés dans le cadre de ce projet avec son aimable autorisation.
Merci à eux !!
Toute la propriété intellectuelle leur appartient, ce système est une adaptation destinée à fonctionner sous FoundryVTT.
Toute la propriété intellectuelle leur appartient, ce système est une adpatation destinée à fonctionner sous FoundryVTT.
L'ensemble du code est sous licence Creative Commons.

View File

@@ -1 +0,0 @@
<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="M259.063 25.094c-56.045 0-106.836 9.775-144.438 26.125-18.8 8.174-34.34 17.96-45.594 29.53-11.254 11.57-18.28 25.338-18.28 40.188 0 9.936 3.17 19.388 8.625 28.03-10.218 21.883-15.844 45.794-15.844 70.782 0 103.158 95.757 187.844 215.532 187.844 119.776 0 215.563-84.686 215.563-187.844 0-24.99-5.653-48.897-15.875-70.78 5.454-8.644 8.625-18.096 8.625-28.032 0-14.85-7.026-28.617-18.28-40.188-11.256-11.57-26.825-21.356-45.626-29.53-37.603-16.35-88.363-26.126-144.408-26.126zm0 18.687c53.848 0 102.554 9.6 136.968 24.564 17.208 7.482 30.775 16.306 39.658 25.437 8.882 9.133 13 18.115 13 27.157 0 9.043-4.118 18.057-13 27.188-8.883 9.13-22.45 17.956-39.657 25.438-34.413 14.963-83.12 24.562-136.967 24.562-53.85 0-102.555-9.6-136.97-24.563-17.206-7.48-30.804-16.306-39.687-25.437-8.882-9.13-12.97-18.145-12.97-27.188 0-9.042 4.088-18.024 12.97-27.156 8.883-9.13 22.48-17.954 39.688-25.436 34.414-14.964 83.12-24.563 136.97-24.563zm-7.782 17.282c-80.57 0-146 26.008-146 57.844 0 31.836 65.43 57.81 146 57.813 40.04 0 76.404-6.613 102.782-16.94-21.316 3.34-45.064 5.845-70.656 5.845-86.066 0-155.937-21.656-155.937-47.906s69.868-47.282 155.936-47.282c20.43 0 39.926.725 57.813 2.906-24.816-7.704-55.957-12.28-89.94-12.28zM87.657 360.5c-9.916 19.897-14.758 36.638-15.78 49.03-1.23 14.906 2.752 22.238 6.655 24.626 3.905 2.388 11.497 2.48 23.376-5.75 9.25-6.41 20.16-17.73 31.375-34.406-16.778-9.432-32.1-20.71-45.624-33.5zm342.75.063c-13.532 12.782-28.872 24.043-45.656 33.468 11.21 16.666 22.13 27.97 31.375 34.376 11.88 8.23 19.472 8.138 23.375 5.75 3.903-2.388 7.886-9.72 6.656-24.625-1.022-12.38-5.855-29.098-15.75-48.967zm-199.25 64.25c1.36 21.275 5.296 37.554 10.344 48.468 6.272 13.56 13.26 17.82 17.72 17.908 4.457.088 11.14-3.683 17.374-16.907 5.133-10.89 9.165-27.52 10.437-49.467a267.366 267.366 0 0 1-27.967 1.468c-9.437 0-18.75-.506-27.907-1.467z" fill="#fff" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -1,66 +0,0 @@
<?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 323.9906 329.83231"
version="1.1"
id="svg6"
sodipodi:docname="weak.svg"
width="323.9906"
height="329.83231"
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="2230"
inkscape:window-height="1388"
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="157.6092"
inkscape:cy="192.4342"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg6" />
<g
class=""
transform="translate(-98.3908,-91.5658)"
id="g4">
<path
d="M 200.094,21.094 213.969,164.814 83.72,58.343 156.344,198.249 78.624,168.779 112.906,230.905 30.844,228.843 135.874,297 31.75,327.03 141.188,348.188 c 8.39,-48.802 49.597,-85.194 97.75,-105.344 28.916,-12.1 60.67,-18.762 90.75,-18.594 19.237,0.108 37.776,3.024 54.437,9.063 l 48,-119.375 L 350,196.5 369.22,34.72 327.344,130.688 313.47,92.03 l -32.69,83.5 z m 255.78,190.687 c -17.883,-0.093 -38.852,9.04 -55.937,26.126 a 100.103,100.103 0 0 0 -13.562,16.875 C 357.123,237.155 314,237.977 273.095,250.877 c -9.17,2.484 -18.214,5.537 -26.94,9.188 -43.676,18.277 -78.503,49.837 -86.218,89.625 -6.61,30.108 5.37,63.223 47.438,94.843 H 88.062 l -26.437,47.75 H 318.78 l -88.467,-103.25 c 24.27,-26.707 67.457,-43.703 97,-45.06 13.792,45.096 36.233,113.496 71.718,148.31 h 60.876 c -43.07,-46.546 -76.57,-109.087 -81.97,-179.842 a 33.579,33.579 0 0 0 6.314,8.78 c 18.664,18.664 55.945,11.618 83.28,-15.718 27.337,-27.336 34.384,-64.618 15.72,-83.28 -7,-7 -16.645,-10.382 -27.375,-10.44 z"
fill="#ffffff"
fill-opacity="1"
transform="matrix(0.7,0,0,0.7,76.8,76.8)"
id="path2" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -1,126 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="80.64064mm"
height="87.145065mm"
viewBox="0 0 80.64064 87.145065"
version="1.1"
id="svg857"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
sodipodi:docname="chance.svg">
<defs
id="defs851">
<linearGradient
inkscape:collect="always"
id="linearGradient2797">
<stop
style="stop-color:#800000;stop-opacity:1;"
offset="0"
id="stop2793" />
<stop
style="stop-color:#800000;stop-opacity:0;"
offset="1"
id="stop2795" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient845"
osb:paint="gradient">
<stop
style="stop-color:#800000;stop-opacity:1;"
offset="0"
id="stop841" />
<stop
style="stop-color:#800000;stop-opacity:0;"
offset="1"
id="stop843" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2797"
id="radialGradient2799"
cx="150.29712"
cy="162.02298"
fx="150.29712"
fy="162.02298"
r="148.85666"
gradientTransform="matrix(1,0,0,1.0817371,0,-13.243291)"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8510546"
inkscape:cx="440.18041"
inkscape:cy="219.34219"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
inkscape:window-width="3840"
inkscape:window-height="2054"
inkscape:window-x="-11"
inkscape:window-y="-11"
inkscape:window-maximized="1" />
<metadata
id="metadata854">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-65.513013,-104.59413)">
<g
id="g7-6"
transform="matrix(0.26458333,0,0,0.26458333,68.622737,106.83336)"
style="opacity:1;mix-blend-mode:normal;fill:#000000;fill-opacity:0.604288;stroke:none;stroke-width:10.56;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.4;image-rendering:auto">
<title
id="title4-3">Layer 1</title>
<path
fill="#ffffff"
fill-rule="evenodd"
stroke="#000000"
stroke-width="8"
id="path2-1"
d="m 206.5,1.5 q 8.5,0 15,3 6.5,3 12.25,8.25 5.75,5.25 12.5,15.5 Q 253,38.5 259.5,43 266,47.5 273.75,52.25 281.5,57 285.5,63 q 4,6 5.75,11.5 1.75,5.5 0,18 -1.75,12.5 -5.75,20 -4,7.5 -12.75,14.25 -8.75,6.75 -17.25,10.75 -8.5,4 -15,6 -6.5,2 -28.75,4.25 -22.25,2.25 -23,3 l -0.75,0.75 0.5,1.25 q 0.5,1.25 32,0.5 31.5,-0.75 43.5,2.75 12,3.5 18.25,8.25 6.25,4.75 9.75,10.25 3.5,5.5 5.5,10.5 2,5 0.5,19.5 -1.5,14.5 -4.75,19.75 -3.25,5.25 -3.75,6.5 l -0.5,1.25 -4.25,2.5 q -4.25,2.5 -10.25,10.5 -6,8 -10,16.5 -4,8.5 -6.75,12.25 -2.75,3.75 -5.25,5.5 -2.5,1.75 -4,4 -1.5,2.25 -9.5,6.25 -8,4 -18.5,2.5 Q 210,290.5 202.75,285.25 195.5,280 190.5,275 q -5,-5 -10.25,-12.25 -5.25,-7.25 -7,-10.5 Q 171.5,249 169,237 q -2.5,-12 -5.5,-21 l -3,-9 -1.5,6.5 q -1.5,6.5 0,28.5 1.5,22 6.5,35 5,13 9.25,18.25 4.25,5.25 10,10.5 5.75,5.25 4.75,10.75 -1,5.5 -1.25,5.75 L 188,322.5 181,321 q -7,-1.5 -13.75,-7.25 Q 160.5,308 156,301.5 q -4.5,-6.5 -8.5,-17 -4,-10.5 -5.5,-20.5 -1.5,-10 -0.25,-36.25 l 1.25,-26.25 -3.25,0.75 q -3.25,0.75 -4.75,5.25 -1.5,4.5 -5.5,29.5 -4,25 -8,32.5 -4,7.5 -7.25,10.75 -3.25,3.25 -8.25,6.75 -5,3.5 -11,5.5 -6,2 -19,0.5 Q 63,291.5 57,288 51,284.5 43.25,274.75 35.5,265 31.75,257 L 28,249 26.5,247.75 Q 25,246.5 20.75,242.75 16.5,239 10,230.5 3.5,222 2.5,219 1.5,216 3,202.5 4.5,189 9.5,181 14.5,173 21.75,167.25 29,161.5 37,158.5 q 8,-3 36.5,-3.5 28.5,-0.5 30.75,-2.75 l 2.25,-2.25 -1.25,-1.25 Q 104,147.5 74,145 44,142.5 30.5,136.5 17,130.5 11.75,125.25 6.5,120 4.5,116.5 2.5,113 2,103.5 1.5,94 5.25,84.75 9,75.5 21.5,65 34,54.5 35,54.25 L 36,54 37.5,51.25 Q 39,48.5 46.25,39.25 53.5,30 57.25,25.75 61,21.5 68,16 75,10.5 83,8 91,5.5 97,6 q 6,0.5 14,4 8,3.5 14.25,9.25 6.25,5.75 9.25,12.25 3,6.5 4.5,15.5 1.5,9 4.25,34 2.75,25 3.75,25 h 1 l 0.75,-2.5 Q 149.5,101 151.5,72 153.5,43 155,39.5 156.5,36 162.25,27.75 168,19.5 176,13.5 q 8,-6 15,-9 7,-3 15.5,-3 z"
style="fill:#000000;fill-opacity:0.604288;stroke:none;stroke-width:10.56;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.4" />
</g>
<g
id="g7"
transform="matrix(0.26458333,0,0,0.26458333,66.057598,105.25559)"
style="opacity:1;mix-blend-mode:normal;fill:#217821;stroke:none;stroke-width:10.56;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.4;image-rendering:auto">
<title
id="title4"
style="stroke:url(#radialGradient2799)">Layer 1</title>
<path
fill="#ffffff"
fill-rule="evenodd"
stroke="#000000"
stroke-width="8"
id="path2"
d="m 206.5,1.5 q 8.5,0 15,3 6.5,3 12.25,8.25 5.75,5.25 12.5,15.5 Q 253,38.5 259.5,43 266,47.5 273.75,52.25 281.5,57 285.5,63 q 4,6 5.75,11.5 1.75,5.5 0,18 -1.75,12.5 -5.75,20 -4,7.5 -12.75,14.25 -8.75,6.75 -17.25,10.75 -8.5,4 -15,6 -6.5,2 -28.75,4.25 -22.25,2.25 -23,3 l -0.75,0.75 0.5,1.25 q 0.5,1.25 32,0.5 31.5,-0.75 43.5,2.75 12,3.5 18.25,8.25 6.25,4.75 9.75,10.25 3.5,5.5 5.5,10.5 2,5 0.5,19.5 -1.5,14.5 -4.75,19.75 -3.25,5.25 -3.75,6.5 l -0.5,1.25 -4.25,2.5 q -4.25,2.5 -10.25,10.5 -6,8 -10,16.5 -4,8.5 -6.75,12.25 -2.75,3.75 -5.25,5.5 -2.5,1.75 -4,4 -1.5,2.25 -9.5,6.25 -8,4 -18.5,2.5 Q 210,290.5 202.75,285.25 195.5,280 190.5,275 q -5,-5 -10.25,-12.25 -5.25,-7.25 -7,-10.5 Q 171.5,249 169,237 q -2.5,-12 -5.5,-21 l -3,-9 -1.5,6.5 q -1.5,6.5 0,28.5 1.5,22 6.5,35 5,13 9.25,18.25 4.25,5.25 10,10.5 5.75,5.25 4.75,10.75 -1,5.5 -1.25,5.75 L 188,322.5 181,321 q -7,-1.5 -13.75,-7.25 Q 160.5,308 156,301.5 q -4.5,-6.5 -8.5,-17 -4,-10.5 -5.5,-20.5 -1.5,-10 -0.25,-36.25 l 1.25,-26.25 -3.25,0.75 q -3.25,0.75 -4.75,5.25 -1.5,4.5 -5.5,29.5 -4,25 -8,32.5 -4,7.5 -7.25,10.75 -3.25,3.25 -8.25,6.75 -5,3.5 -11,5.5 -6,2 -19,0.5 Q 63,291.5 57,288 51,284.5 43.25,274.75 35.5,265 31.75,257 L 28,249 26.5,247.75 Q 25,246.5 20.75,242.75 16.5,239 10,230.5 3.5,222 2.5,219 1.5,216 3,202.5 4.5,189 9.5,181 14.5,173 21.75,167.25 29,161.5 37,158.5 q 8,-3 36.5,-3.5 28.5,-0.5 30.75,-2.75 l 2.25,-2.25 -1.25,-1.25 Q 104,147.5 74,145 44,142.5 30.5,136.5 17,130.5 11.75,125.25 6.5,120 4.5,116.5 2.5,113 2,103.5 1.5,94 5.25,84.75 9,75.5 21.5,65 34,54.5 35,54.25 L 36,54 37.5,51.25 Q 39,48.5 46.25,39.25 53.5,30 57.25,25.75 61,21.5 68,16 75,10.5 83,8 91,5.5 97,6 q 6,0.5 14,4 8,3.5 14.25,9.25 6.25,5.75 9.25,12.25 3,6.5 4.5,15.5 1.5,9 4.25,34 2.75,25 3.75,25 h 1 l 0.75,-2.5 Q 149.5,101 151.5,72 153.5,43 155,39.5 156.5,36 162.25,27.75 168,19.5 176,13.5 q 8,-6 15,-9 7,-3 15.5,-3 z"
style="fill:#217821;stroke:none;stroke-width:10.56;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.4" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -1,90 +0,0 @@
<?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 437.49716 437.38699"
version="1.1"
id="svg13"
sodipodi:docname="destinee.svg"
width="437.49716"
height="437.38699"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata17">
<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>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1776"
inkscape:window-height="1711"
id="namedview15"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="1.4355469"
inkscape:cx="217.3254"
inkscape:cy="228.937"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg13" />
<defs
id="defs7">
<radialGradient
id="lorc-aura-gradient-1"
gradientTransform="scale(1.0001259,0.9998741)"
cx="257.54889"
cy="253.53915"
fx="257.54889"
fy="253.53915"
r="243.02338"
gradientUnits="userSpaceOnUse">
<stop
offset="0%"
stop-color="#f8e71c"
stop-opacity="1"
id="stop2" />
<stop
offset="100%"
stop-color="#f5a623"
stop-opacity="0.53"
id="stop4" />
</radialGradient>
</defs>
<g
class=""
transform="translate(-38.6746,-35.063004)"
id="g11">
<path
d="m 320.938,13.28 c -16.646,34.584 -38.466,60.157 -63.094,60.157 -24.522,0 -47.035,-25.275 -63.656,-59.593 0.366,39.358 -9.71,90.884 -30.938,105.125 -21.228,14.24 -49.64,-12.002 -78.844,-32.126 17.455,34.04 42.095,67.5 29.78,92.28 -12.21,24.576 -59.172,35.96 -92.874,35.626 29.338,19.29 78.842,45.803 78.844,74.188 0.002,28.384 -49.504,53.71 -78.844,73 33.702,-0.333 80.663,11.612 92.876,36.187 12.227,24.61 -9.03,56.31 -33.75,85.563 44.826,-15.413 65.142,-5.735 85.374,10.812 h 31.75 C 154.822,459.086 125.5,386.671 125.5,302.936 125.498,184.316 184.42,88.03 256.906,88.03 c 72.488,0 131.406,96.29 131.406,214.907 0,83.74 -29.317,156.153 -72.062,191.563 h 27.313 c 19.847,-14.62 39.796,-25.65 89.687,-9.28 -26.233,-30.264 -42.2,-62.484 -29.97,-87.095 12.257,-24.665 56.658,-36.612 90.533,-36.188 -29.4,-19.297 -75.344,-44.584 -75.344,-73 0,-28.415 45.943,-54.89 75.342,-74.187 -33.874,0.424 -78.273,-10.962 -90.53,-35.625 -12.315,-24.78 9.982,-58.24 27.437,-92.28 -29.202,20.12 -57.583,46.385 -78.845,32.124 -21.262,-14.263 -31.382,-66.13 -30.938,-105.69 z m -68.97,93.75 c -19.56,2.543 -37.343,25.564 -37.343,55.407 0,16.447 5.67,30.986 14,41.032 l 10.156,12.218 -15.593,2.937 c -10.815,2.035 -18.743,7.737 -25.53,17.063 -6.79,9.325 -11.984,22.344 -15.626,37.343 -6.585,27.128 -8.078,60.24 -8.31,89.47 h 36.093 l 0.656,8.656 9.124,122.563 h 76.187 l 8.095,-122.5 0.563,-8.72 h 34.375 c -0.026,-29.592 -0.44,-63.166 -6.407,-90.5 -3.295,-15.095 -8.287,-28.096 -15.156,-37.313 -6.87,-9.216 -15.133,-14.897 -27.28,-16.78 l -15.94,-2.47 10.064,-12.593 c 7.97,-9.996 13.375,-24.36 13.375,-40.406 -0.002,-31.817 -19.884,-55.313 -41.44,-55.313 -2.54,0 -3.96,-0.103 -4.03,-0.094 h -0.03 z"
fill="url(#lorc-aura-gradient-1)"
stroke="#d03d02"
stroke-opacity="1"
stroke-width="4"
transform="matrix(0.9,0,0,0.9,25.6,25.6)"
id="path9"
style="fill:url(#lorc-aura-gradient-1)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -1,66 +0,0 @@
<?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 410.39459 390.34079"
version="1.1"
id="svg6"
sodipodi:docname="encaisser.svg"
width="410.39459"
height="390.34079"
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="2284"
inkscape:window-height="1517"
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="206.1036"
inkscape:cy="215.2477"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg6" />
<g
class=""
transform="translate(-49.8964,-68.7523)"
id="g4">
<path
d="m 26.996,47.947 c 11.726,44.806 56.176,129.96 67.496,242.934 -6.597,76.494 -22.66,98.81 -22.66,152.74 0,27.602 11.33,38.038 23.254,38.038 11.662,0 23.72,-11.823 23.72,-40.896 0,-56.606 -16.937,-73.84 -23.283,-151.65 6.472,-83.65 59.715,-45.933 59.715,2.765 0,-112.652 101.99,-85.16 116.024,-34.77 -5.164,35.11 -15.028,45.947 -15.028,75.368 0,16.633 8.51,28.86 16.74,28.86 8.416,0 16.41,-11.433 16.41,-27.226 0,-27.953 -9.303,-41.066 -14.515,-75.825 15.447,-37.68 115.544,-34.583 115.845,-1.754 -3.41,26.414 -12.764,32.13 -12.764,51.16 0,9.714 6.58,16.855 12.943,16.855 6.506,0 12.685,-6.677 12.685,-15.9 0,-18.435 -9.164,-25.838 -12.596,-52.854 14.138,-49.16 86.57,-19.867 92.008,-73.298 -51.22,45.91 -357.175,26.76 -455.994,-134.545 z m 128.85,266.22 c -4.676,31.802 -17.635,40.28 -17.635,61.724 0,10.642 8.592,18.346 17.636,18.346 8.844,0 17.988,-8.24 17.988,-19.45 0,-22.338 -13.464,-28.757 -17.988,-60.62 z"
fill="#ffffff"
transform="matrix(0.9,0,0,0.9,25.6,25.6)"
fill-opacity="1"
id="path2" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -1 +0,0 @@
<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="M249.094 18.25c-42.675 0-81.852 25.486-110.938 68.438C109.07 129.637 90.72 189.74 90.72 256.28c0 66.543 18.35 126.643 47.436 169.595s68.263 68.47 110.938 68.47 81.883-25.518 110.97-68.47c29.084-42.952 47.436-103.052 47.436-169.594 0-66.54-18.352-126.64-47.438-169.592C330.978 43.736 291.77 18.25 249.094 18.25zm-128.97 241.313c18.356 18.096 37.528 26.765 55.72 27.562 18.19.797 35.927-6.096 52.125-21.5l12.874 13.53c-19.214 18.274-42.25 27.658-65.813 26.626-23.56-1.03-47.1-12.3-68-32.905l13.095-13.313zm264.782 0 13.125 13.312C377.135 293.48 353.564 304.75 330 305.78c-23.563 1.033-46.598-8.35-65.813-26.624l12.875-13.53c16.2 15.403 33.934 22.296 52.125 21.5 18.192-.798 37.365-9.467 55.72-27.563zM251.562 371.656c36.423-.156 72.996 19.144 77.438 58.406-51.33 13.296-102.67 12.767-154 0 3.858-38.638 40.14-58.25 76.563-58.406z" fill="#fff" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1 +0,0 @@
<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="M45.95 14.553c-19.38.81-30.594 11.357-30.282 30.283l19.768 30.78c4.43-1.213 9.36-3.838 14.248-7.335l42.474 59.935c-17.018 20.83-31.258 44.44-42.71 70.836l26.55 26.552c11.275-23.6 24.634-44.826 39.918-63.864l210.82 297.475 166.807 33.213L460.33 325.62 162.78 114.745c19.907-16.108 41.842-29.91 65.652-41.578l-26.553-26.55c-27.206 11.803-51.442 26.576-72.735 44.292L69.39 48.56c3.443-4.823 6.062-9.735 7.342-14.242l-30.78-19.765zm400.84 86.933v.008l.003-.008h-.002zm0 .008-28.028 124.97-25.116-80.593-18.105 70.667-26.862-49.64-.584 57.818 128.484 91.69 15.184 87.017-1.168-186.885-34.457 39.713-9.346-154.756zm-300.95 27.98 222.224 196.368 25.645 66.75-66.75-25.645L130.6 144.734a308.453 308.453 0 0 1 15.238-15.26zm32.305 196.274v.004h.005l-.005-.004zm.005.004 28.028 22.775-36.21 4.088 57.82 19.272-105.706 4.09 115.05 27.45L136.1 422.114l127.316 25.696-67.164 43.803 208.494 1.752-87.017-15.185-104.54-150.676-35.037-1.752z" fill="#fff" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1 +0,0 @@
<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="M227.227 21.777c-1.845 0-3.704.05-5.567.157-15.314.875-30.76 5.305-39.494 10.863l-.008 73.15c2.884-.094 5.777-.147 8.676-.142 23.382.036 47.104 3.286 68.47 9.513l.01-87.507c-7.034-3.518-19.178-6.03-32.087-6.033zm80.74 9.16c-11.925.15-23.077 2.364-29.967 5.596l-.008 77.602v7.658c38.486 15.67 64.814 42.48 58.735 78.764l-.96 5.73-5.562 1.674c-17.45 5.253-34.872 9.703-52.225 13.335v25.234c25.562-.704 51.327-2.687 77.145-6.098l.02-197.928c-8.284-5.563-23.508-10.243-38.842-11.328a100.065 100.065 0 0 0-8.336-.238zM143.223 46.294a99.206 99.206 0 0 0-16.491 1.172c-15.67 2.454-31.477 8.565-40.406 15.402l-.01 72.955c18.808-15.81 46.704-25.143 77.15-28.54l.007-57.966c-4.82-1.752-12.018-2.916-20.25-3.023zm258.394 3.46c-10.804.117-20.722 1.93-27.043 4.655l-.02 183.182c25.074-4.02 50.16-9.412 75.122-16.358l1.99-158.447c-8.352-5.9-23.648-11.025-39.05-12.553a100.98 100.98 0 0 0-11-.478zm-222.775 74.202c-53.72.702-101.407 20.365-97.887 66.6 15.836-3.918 30.84-5.893 44.94-6.1 34.84-.51 64.213 9.704 87.318 27.613 34.608-3.11 69.852-10 105.412-20.314.14-41.287-74.098-68.657-139.783-67.8zm-48.877 78.65c-1.296-.003-2.603.012-3.92.045-17.256.436-36.45 4.03-57.566 11.037 5.79 53.808 26.325 106.41 58.5 143.346 6.226 7.15 12.856 13.712 19.875 19.615 29.303 9.282 69.26 12.917 110.534 12.14 3.777-55.805-8.717-108.357-36.193-142.74-21.265-26.61-51.064-43.39-91.232-43.444zm129.326 22.282a545.177 545.177 0 0 1-27.995 4.15 138.77 138.77 0 0 1 4.502 5.346c3.146 3.937 6.094 8.062 8.873 12.334 9.916.144 19.868.125 29.857-.106H259.29v-21.723zm191.817 15.343c-65.406 17.826-131.462 25.41-195.85 25.315 16.998 35.144 23.828 78.093 21.013 122.6 42.482-2.08 85.03-8.23 118.187-15.983 26.693-32.78 47.37-77.118 56.65-131.932zM400.51 389.9c-38.334 9.145-87.95 16.056-136.873 17.454-47.67 1.36-94.336-2.228-129.448-15.262l-.01 78.93c27.187 12.568 76.414 20.205 127.318 20.298 51.224.094 104.214-7.173 139-20.773l.012-80.647z" fill="#fff" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -1 +0,0 @@
<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="M275.03 20c35.223 49.563 53.59 113.64 55.69 173.47C315.154 143 289.092 88.423 250.81 48.75c40.294 79.527 51.15 172.312 37.938 256.094-12.287-75.777-40.564-159.524-92.375-227.156 29.6 70.937 36.64 149.785 24.813 221.843-8.745-51.804-25.41-107.4-52.594-158.81 13.023 54.315 12.854 107.64 3.437 159.28l21.657 6.813 15 4.718-11.28 10.908c-10.68 10.332-19.868 21.905-27.345 34.343 93.614 35.486 232.952 64.53 298.032 41.376-41.02 56.466-210.332 13.822-309.313-18.687-1.514 3.775-2.918 7.594-4.124 11.467a152.536 152.536 0 0 0-6.062 29.657l176.47 66.375c98.5 31.095 150.5-24.62 158.655-81.72C505.253 254.472 485.016 105.66 426.06 20h-22.187c40.092 65.52 66.67 154.216 60.47 255.344-8.154-79.833-42.8-157.214-98.44-219.5 38.676 85.094 56.566 185.746 34.376 288.625.057-118.816-33.1-225.865-105.092-324.47H275.03zm-110.186 1.594c41.255 29.176 74.328 74.093 97.5 120.656-7.702-46.15-21.3-86.79-44-120.656h-53.5zm176.375 0c28.882 15.143 52.096 36.614 71.28 66.78-7.14-27.79-17.217-49.85-31.438-66.78H341.22zM123.686 304.406a179.344 179.344 0 0 1-4.062 64L18.812 336.344V366l91.938 29.094a178.602 178.602 0 0 1-30.313 48.28l50.094 15.75c-3.038-24.898-1.136-49.885 6.282-73.718 7.446-23.92 20.223-46.108 37.032-65.22l-50.156-15.78z" fill="#fff" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,66 +0,0 @@
<?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 433.39499 347.36221"
version="1.1"
id="svg6"
sodipodi:docname="recul.svg"
width="433.39499"
height="347.36221"
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="1053"
inkscape:window-height="498"
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="216.6975"
inkscape:cy="201.682"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg6" />
<g
class=""
transform="translate(-39.3025,-82.318)"
id="g4">
<path
d="M 274.663,63.02 90.792,80.26 244.985,99.533 c 5.063,-13.339 12.952,-24.341 22.541,-31.828 a 52.072,52.072 0 0 1 7.137,-4.683 z m 19.832,12.803 c -5.092,0.166 -10.492,2.296 -15.879,6.502 -7.835,6.118 -15.009,16.575 -18.83,29.688 -3.821,13.112 -3.477,26.099 -0.289,35.927 3.188,9.829 8.73,16.071 15.633,18.395 6.903,2.324 14.766,0.596 22.601,-5.522 7.835,-6.117 15.01,-16.574 18.83,-29.687 3.822,-13.113 3.48,-26.1 0.292,-35.928 -3.189,-9.828 -8.73,-16.07 -15.633,-18.394 a 19.017,19.017 0 0 0 -6.725,-0.98 z m 166.85,9.485 c -24.113,13.949 -46.193,20.298 -87.233,17.252 L 340.48,228.452 c -0.675,2.682 -0.318,6 1.922,10.87 2.243,4.876 6.355,10.89 11.836,17.607 9.99,12.242 24.527,27.16 39.573,44.238 14.56,-5.5 28.23,-12.828 38.972,-20.19 11.841,-8.113 20.234,-16.95 21.965,-19.939 l 42.027,-118.22 c -16.748,-14.613 -29.471,-33.974 -35.43,-57.51 z m -288.07,51.261 -149.623,21.762 89.309,12.988 2.158,-5.052 z m 286.265,2.325 16.941,6.078 -39.123,109.037 -37.212,19.181 -8.247,-15.998 30.913,-15.933 z m -259.842,4.394 -70.586,36.043 -29.222,68.422 19.218,8.809 24.905,-57.764 59.299,-22.973 -14.702,75.955 -0.963,1.477 c -32.725,50.18 -71.654,93.41 -118.464,134.28 l -26.461,45.443 17.021,7.245 31.875,-43.989 1.38,-0.906 c 45.476,-29.872 75.93,-62.333 112.255,-94.492 l 4.533,-4.012 5.426,2.686 c 23.365,11.571 42.934,24.117 62.107,37.705 l 8.924,6.324 -69.006,65.643 24.649,39.794 17.67,-10.308 -20.078,-28.477 8.224,-5.004 c 29.884,-18.186 49.986,-39.43 71.938,-66.039 -23.653,-35.6 -42.006,-49.433 -71.592,-71.267 l 9.908,-7.227 c 34.703,-25.312 38.132,-54.476 41.61,-79.449 -9.203,4.441 -19.498,5.772 -29.473,2.414 -13.488,-4.54 -22.924,-16.472 -27.465,-30.473 -0.17,-0.522 -0.321,-1.054 -0.479,-1.584 z m 116.62,45.04 c -1.355,7.027 -3.324,14.17 -6.092,21.349 l 14.056,9.666 5.938,-22.223 z m -174.243,97.476 -126.85,17.953 99.67,14.105 a 598.987,598.987 0 0 0 27.18,-32.058 z m 91.781,82.73 -95.892,21.432 59.406,13.277 z"
fill="#ffffff"
fill-opacity="1"
transform="matrix(0.9,0,0,0.9,25.6,25.6)"
id="path2" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.7 KiB

View File

@@ -1,59 +1,13 @@
# 13.0
## 13.0.11 - Le gambit d'Illysis
- Nouvelle fenêtre de jets de dés
- jeux
- cuisine et préparation de nourriture
## 13.0.10 - Les papilles d'Illysis
- Ajout d'un statut "saignement" en cas de blessure grave ou critique sans premiers soins
- Nouvelle fenêtre de jets de dés
- jets de méditation
- jets de tâches
- jets de caractéristiques
- jets de compétences
- Boutons d'initiative et d'attaque V2
- fenêtre d'attaque
- choix des armes
- gestion des particulières
- message au défenseur
- gestion des demi-surprises (attaquant/défenseur)
- gestion des tactiques (attaquant/défenseur)
- en cours nouvelle fenêtre de jets
- jets de compétence avec messages
- jets de cuisine séparés avec messages (pour gérer plus tard les spécificités: fabricatioon de plats)
- gestion des empoignades
- Technique: suppression de warnings foundry sur renderTemplate
## 13.0.9 - Le combat d'Illysis
- Fix
- La montée en TMR fonctionne
- ajout d'un status "Force insuffisante"
- clarification des maladresses à l'attaque (en demi surprise, ou à cause d'un échec total)
- Nouvelle fenêtre de jets de dés
- ajout du statut "Force insuffisante" aux acteurs si la
force est insuffisante pour l'arme
- avancement du mode attaque
- choix de tactique
- choix mortel/non-mortel pour les dommages
- affichage des dommages ajustés delon les choix
- affichage du statut de surprise de l'attaquant
- affichage du statut de surprise du défenseur
- prise en compte des significatives (demi-surprises)
- avancement du mode défense
- sélection esquive/parade
- affichage du statut de surprise du défenseur
- prise en compte des significatives (demi-surprises, armes disparates,
particulière en finesse)
- gestion de l'appel à la chance
- gestion de l'utilisation de la destinée
- gestion du recul depuis le messages
- gestion de l'encaissement depuis le messages
- impossible de faire un jet "actif" en surprise totale (attaque, parade, ...)
- choix des dommages, affichage
- affichage de la surprise du défenseur
## 13.0.8 - Le renouveau d'Illysis

View File

@@ -96,7 +96,6 @@ select,
--gradient-red: linear-gradient(150deg, rgba(255, 0, 0, 0.3), rgba(255, 200, 128, 0.05), rgba(255, 200, 128, 0.1), rgba(255, 10, 0, 0.3));
--gradient-violet: linear-gradient(150deg, rgba(100, 45, 124, 0.6), rgba(216, 157, 192, 0.3), rgba(177, 157, 216, 0.5), rgba(107, 62, 121, 0.3), rgba(100, 45, 124, 0.6));
--gradient-purple-black: linear-gradient(150deg, rgba(0, 0, 0, 0.7), rgba(100, 45, 124, 0.4), rgba(82, 17, 131, 0.3), rgba(100, 45, 124, 0.4), rgba(0, 0, 0, 0.7));
--gradient-warning: linear-gradient(150deg, hsla(32, 100%, 50%, 0.3), hsla(52, 60%, 50%, 0.1), hsla(32, 60%, 50%, 0.1), hsla(32, 100%, 50%, 0.3));
--gradient-silver-light: linear-gradient(30deg, rgba(61, 55, 93, 0.2), rgba(178, 179, 196, 0.1), rgba(59, 62, 63, 0.2), rgba(206, 204, 199, 0.1), rgba(61, 46, 49, 0.2));
--gradient-daylight: conic-gradient(from 0deg, hsla(50, 100%, 80%, 0.7), hsla(30, 30%, 40%, 0.1) 25%, hsla(250, 50%, 40%, 0.1) 25%, hsla(250, 30%, 30%, 0.7) 50%, hsla(250, 50%, 40%, 0.1) 75%, hsla(30, 30%, 40%, 0.1) 75%, hsla(50, 100%, 80%, 0.7));
--background-custom-button: linear-gradient(to bottom, hsla(208, 38%, 21%, 0.988) 5%, hsla(202, 42%, 14%, 0.671) 100%);
@@ -160,7 +159,7 @@ select,
min-height: 100px;
background: var(--rdd-bg-input-alt);
padding: 5px;
border-radius: 0.2rem;
border-radius: 3px;
color: var(--rdd-color-text-primary);
}
.system-foundryvtt-reve-de-dragon .monnaie-content .window-content {
@@ -177,7 +176,7 @@ select,
background: var(--fieldset-background);
color: var(--rdd-color-text-primary);
margin-bottom: 4px;
border-radius: 0.5rem;
border-radius: 6px;
border-color: var(--rdd-color-text-primary);
border-width: 2px;
}
@@ -207,7 +206,7 @@ select,
border: 1px solid var(--rdd-color-border-input);
color: var(--rdd-color-text-input);
padding: 2px 2px;
border-radius: 0.2rem;
border-radius: 3px;
}
.system-foundryvtt-reve-de-dragon .monnaie-content .form-group input[type="checkbox"] {
flex: 0 0 20px;
@@ -251,7 +250,7 @@ select,
min-height: 100px;
background: var(--rdd-bg-input-alt);
padding: 5px;
border-radius: 0.2rem;
border-radius: 3px;
color: var(--rdd-color-text-primary);
}
.system-foundryvtt-reve-de-dragon .munition-content .window-content {
@@ -268,7 +267,7 @@ select,
background: var(--fieldset-background);
color: var(--rdd-color-text-primary);
margin-bottom: 4px;
border-radius: 0.5rem;
border-radius: 6px;
border-color: var(--rdd-color-text-primary);
border-width: 2px;
}
@@ -298,7 +297,7 @@ select,
border: 1px solid var(--rdd-color-border-input);
color: var(--rdd-color-text-input);
padding: 2px 2px;
border-radius: 0.2rem;
border-radius: 3px;
}
.system-foundryvtt-reve-de-dragon .munition-content .form-group input[type="checkbox"] {
flex: 0 0 20px;
@@ -342,7 +341,7 @@ select,
min-height: 100px;
background: var(--rdd-bg-input-alt);
padding: 5px;
border-radius: 0.2rem;
border-radius: 3px;
color: var(--rdd-color-text-primary);
}
.system-foundryvtt-reve-de-dragon .tarot-content .window-content {
@@ -359,7 +358,7 @@ select,
background: var(--fieldset-background);
color: var(--rdd-color-text-primary);
margin-bottom: 4px;
border-radius: 0.5rem;
border-radius: 6px;
border-color: var(--rdd-color-text-primary);
border-width: 2px;
}
@@ -389,7 +388,7 @@ select,
border: 1px solid var(--rdd-color-border-input);
color: var(--rdd-color-text-input);
padding: 2px 2px;
border-radius: 0.2rem;
border-radius: 3px;
}
.system-foundryvtt-reve-de-dragon .tarot-content .form-group input[type="checkbox"] {
flex: 0 0 20px;
@@ -425,7 +424,7 @@ select,
.system-foundryvtt-reve-de-dragon .roll-dialog {
font-family: CaslonAntique;
display: grid;
grid-template-areas: "header header header header header header header" "action action action action action action action" "type separation separation separation separation separation separation" "type carac carac carac comp comp resume" "type choix choix choix choix choix conditions" "type resolution resolution resolution resolution resolution conditions" "type chances chances chances chances chances buttons" "footer footer footer footer footer footer footer";
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;
}
@@ -451,7 +450,7 @@ select,
grid-area: resolution;
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions {
grid-area: conditions;
grid-area: modifiers;
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-chances {
grid-area: chances;
@@ -462,26 +461,26 @@ select,
.system-foundryvtt-reve-de-dragon .roll-dialog roll-buttons {
grid-area: buttons;
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-type {
grid-area: type;
.system-foundryvtt-reve-de-dragon .roll-dialog roll-mode {
grid-area: mode;
display: flex;
flex-direction: column;
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="rollmode"] button[data-checked="true"],
.system-foundryvtt-reve-de-dragon .roll-dialog roll-type button[data-checked="true"] {
.system-foundryvtt-reve-de-dragon .roll-dialog roll-mode button[data-checked="true"] {
background-color: var(--color-text-selection-bg);
color: var(--color-controls);
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="rollmode"] button[data-checked="true"] i,
.system-foundryvtt-reve-de-dragon .roll-dialog roll-type button[data-checked="true"] i {
.system-foundryvtt-reve-de-dragon .roll-dialog roll-mode button[data-checked="true"] i {
filter: invert(0.8);
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="rollmode"] button[data-checked="true"] img,
.system-foundryvtt-reve-de-dragon .roll-dialog roll-type button[data-checked="true"] img {
.system-foundryvtt-reve-de-dragon .roll-dialog roll-mode button[data-checked="true"] img {
filter: invert(0.2);
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="rollmode"] button,
.system-foundryvtt-reve-de-dragon .roll-dialog roll-type button {
.system-foundryvtt-reve-de-dragon .roll-dialog roll-mode button {
height: 1.8rem;
width: 1.8rem;
gap: 0.5rem;
@@ -490,11 +489,11 @@ select,
color: var(--color-controls);
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="rollmode"] button i,
.system-foundryvtt-reve-de-dragon .roll-dialog roll-type button i {
.system-foundryvtt-reve-de-dragon .roll-dialog roll-mode button i {
filter: invert(0.2);
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="rollmode"] button img,
.system-foundryvtt-reve-de-dragon .roll-dialog roll-type button img {
.system-foundryvtt-reve-de-dragon .roll-dialog roll-mode button img {
filter: invert(0.8);
}
.system-foundryvtt-reve-de-dragon .roll-dialog :is(roll-carac, roll-comp) {
@@ -529,10 +528,6 @@ select,
flex-direction: row;
margin: 0.1rem 0;
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section subline .warning {
border-radius: 0.5rem;
background: var(--gradient-warning);
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-img {
display: flex;
flex-direction: column;
@@ -560,29 +555,13 @@ select,
.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline div.poesie-extrait {
display: flex;
flex-direction: column;
align-items: normal;
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline span.status-surprise {
display: flex;
flex-direction: row;
flex-flow: wrap;
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline span.status-surprise img {
filter: invert(0.8);
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline label {
align-content: center;
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-section selected-numeric-value {
display: flow;
width: 2.5rem;
text-align: right;
margin: 0 0.2rem;
margin: 0 0.2rem 0 0.5rem;
padding: 0 0.2rem;
border: 1px solid ;
border-radius: 0.2rem;
height: 1.5rem;
background: hsla(0, 0%, 0%, 0.2);
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-action {
flex-basis: content;
@@ -637,13 +616,12 @@ select,
margin: 0 0.1rem;
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-carac select[name="select-carac"] {
min-width: 6.5rem;
max-width: 8rem;
max-width: 6rem;
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-comp select[name="select-comp"] {
min-width: 8rem;
max-width: 10rem;
margin-left: 1.5rem;
max-width: 11rem;
margin-left: 1rem;
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="coeur"] select[name="coeur"] {
max-width: 4rem;
@@ -666,94 +644,6 @@ select,
width: 1.5rem;
text-align: center;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat {
font-family: CaslonAntique;
display: grid;
grid-template-areas: "img header buttons" "img resume buttons" "details details details" "actions actions actions";
grid-template-columns: 3rem 1fr 1.4rem;
grid-template-rows: max-content max-content max-content max-content;
gap: 0 0.5rem;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-img,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-img {
grid-area: img;
display: flex;
flex-direction: column;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-img img,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-img img {
border: 0;
max-height: 3rem;
max-width: 3rem;
object-fit: contain;
height: 100%;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-header,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-header {
grid-area: header;
font-weight: bold;
font-size: 0.9rem;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-resume,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-resume {
grid-area: resume;
text-align: justify;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-details,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-details {
grid-area: details;
text-align: justify;
display: flex;
flex-direction: column;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-actions {
grid-area: actions;
display: flex;
flex-direction: column;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions a,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-actions a {
display: flex;
flex-direction: row;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions a img,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-actions a img {
margin-right: 0.5rem;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons {
grid-area: buttons;
display: flex;
flex-direction: column;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons a {
border-radius: 0.2rem;
cursor: pointer;
padding: 0.2rem;
position: relative;
box-shadow: inset 1x 1px #a6827e;
color: var(--color-controls);
border: 1px ridge #846109;
display: inline-block;
align-items: center;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a img,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons a img {
max-width: 1rem;
max-height: 1rem;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a:hover,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons a:hover {
background: var(--background-custom-button-hover);
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a:active,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons a:active {
position: relative;
top: 1px;
}
.system-foundryvtt-reve-de-dragon .window-header {
background: rgba(0, 0, 0, 0.75);
}
@@ -1042,18 +932,16 @@ select,
}
.system-foundryvtt-reve-de-dragon .flex-grow,
.system-foundryvtt-reve-de-dragon .flex-grow-3 {
display: flex;
flex-grow: 3;
}
.system-foundryvtt-reve-de-dragon .flex-grow-0-5 {
flex-grow: 0.5;
.system-foundryvtt-reve-de-dragon .flex-grow-2 {
flex-grow: 2;
}
.system-foundryvtt-reve-de-dragon .flex-grow-1 {
flex-grow: 1;
}
.system-foundryvtt-reve-de-dragon .flex-grow-2 {
display: flex;
flex-grow: 2;
.system-foundryvtt-reve-de-dragon .flex-grow-0-5 {
flex-grow: 0.5;
}
.system-foundryvtt-reve-de-dragon .voyage-liste-survies {
max-width: 12rem;
@@ -1096,16 +984,14 @@ select,
justify-content: center;
text-align: center;
}
.system-foundryvtt-reve-de-dragon :is(.item-actions-controls, .equipement-actions) {
.system-foundryvtt-reve-de-dragon .item-actions-controls,
.system-foundryvtt-reve-de-dragon .equipement-actions {
margin: 0;
flex-grow: 1.2;
flex-grow: 2;
align-items: end;
justify-content: flex-end;
text-align: right;
}
.system-foundryvtt-reve-de-dragon .liste-equipement :is(.equipement-actions, .item-actions-controls) {
flex-grow: 2;
}
.system-foundryvtt-reve-de-dragon .blessure-control {
flex-grow: 1;
flex-direction: row;
@@ -1339,6 +1225,15 @@ select,
margin-right: 0.2rem;
margin-left: 0.2rem;
}
.system-foundryvtt-reve-de-dragon .flex-grow-1 {
flex-grow: 1;
}
.system-foundryvtt-reve-de-dragon .flex-grow-2 {
flex-grow: 2;
}
.system-foundryvtt-reve-de-dragon .flex-grow-3 {
flex-grow: 3;
}
.system-foundryvtt-reve-de-dragon fieldset {
border-style: groove;
border-width: 0.1rem;
@@ -1469,38 +1364,38 @@ select,
}
.system-foundryvtt-reve-de-dragon .rdd-roll-part {
align-items: center;
border-radius: 0.5rem;
border-radius: 6px;
padding: 3px;
background: var(--gradient-gold);
}
.system-foundryvtt-reve-de-dragon .rdd-roll-sign {
border-radius: 0.5rem;
border-radius: 6px;
padding: 3px;
background: var(--gradient-silver);
}
.system-foundryvtt-reve-de-dragon .rdd-roll-norm {
border-radius: 0.5rem;
border-radius: 6px;
padding: 3px;
background: var(--gradient-green);
}
.system-foundryvtt-reve-de-dragon .rdd-roll-notSign,
.system-foundryvtt-reve-de-dragon .rdd-roll-echec {
border-radius: 0.5rem;
border-radius: 6px;
padding: 3px;
background: var(--gradient-red);
}
.system-foundryvtt-reve-de-dragon .rdd-roll-epart {
border-radius: 0.5rem;
border-radius: 6px;
padding: 3px;
background: var(--gradient-violet);
}
.system-foundryvtt-reve-de-dragon .rdd-roll-etotal {
border-radius: 0.5rem;
border-radius: 6px;
padding: 3px;
background: var(--gradient-purple-black);
}
.system-foundryvtt-reve-de-dragon .rdd-diviseur {
border-radius: 0.5rem;
border-radius: 6px;
padding: 3px;
background: var(--gradient-red);
}
@@ -1527,8 +1422,12 @@ select,
font-size: 0.8rem;
font-style: italic;
color: rgba(82, 17, 131, 0.9);
overflow-y: scroll;
width: 100%;
overflow: hidden;
}
.system-foundryvtt-reve-de-dragon .poesie-extrait:hover {
max-height: unset;
overflow: visible;
opacity: 1;
}
.system-foundryvtt-reve-de-dragon .poesie-reference {
font-size: 0.7rem;
@@ -1594,7 +1493,7 @@ select,
height: var(--form-field-height);
margin: 0;
color: var(--color-text-dark-primary);
border-radius: 0.2rem;
border-radius: 3px;
}
.system-foundryvtt-reve-de-dragon .app-calendar-astrologie div.theme-astral {
width: 14rem;
@@ -1645,7 +1544,7 @@ select,
background: hsla(280, 50%, 50%, 0.1);
padding: 1px 4px;
border: 1px solid var(--color-border-dark-tertiary);
border-radius: 0.2rem;
border-radius: 2px;
white-space: nowrap;
word-break: break-all;
}
@@ -1655,7 +1554,7 @@ select,
font-weight: 560;
padding: 0.1rem 0.3rem;
border: 1px solid var(--color-border-dark-tertiary);
border-radius: 0.2rem;
border-radius: 0.25rem;
white-space: nowrap;
word-break: break-all;
display: ruby;
@@ -1775,7 +1674,7 @@ select,
.system-foundryvtt-reve-de-dragon .xp-level-up {
margin: 0.1rem;
box-shadow: inset 0px 0px 1px #00000096;
border-radius: 0.2rem;
border-radius: 0.25rem;
padding: 0.1rem;
flex: 1 1 5rem;
background: var(--gradient-gold) !important;
@@ -1806,7 +1705,7 @@ select,
.system-foundryvtt-reve-de-dragon .list-item {
margin: 0.1rem;
box-shadow: inset 0px 0px 1px #00000096;
border-radius: 0.2rem;
border-radius: 0.25rem;
padding: 0.1rem;
flex: 1 1 1.5rem;
display: flex;
@@ -1975,13 +1874,13 @@ select,
justify-content: flex-start;
flex-direction: column;
position: absolute;
top: 10rem;
left: -9rem;
top: 4.6rem;
left: -19rem;
}
.system-foundryvtt-reve-de-dragon .token-hud-ext.soins {
flex-direction: column;
position: absolute;
top: 15.5rem;
top: 14.7rem;
left: -6rem;
max-width: 8rem;
line-height: 1rem;
@@ -1996,18 +1895,14 @@ select,
width: 9rem;
height: fit-content;
border-radius: 0.3rem;
min-width: 8rem;
min-width: 6rem;
flex-basis: auto;
padding: 0;
line-height: 1.6rem;
line-height: 0.95rem;
margin: 0.2rem;
display: flex;
flex-direction: row;
align-items: center;
}
.system-foundryvtt-reve-de-dragon div.control-icon.token-hud-icon select,
.system-foundryvtt-reve-de-dragon div.control-icon.token-hud-icon label {
font-size: 1rem;
.system-foundryvtt-reve-de-dragon .rdd-hud-menu label {
font-size: 0.8rem;
}
.system-foundryvtt-reve-de-dragon .item-checkbox {
height: 25px;
@@ -2085,13 +1980,11 @@ select,
flex-grow: 2;
}
.system-foundryvtt-reve-de-dragon #sidebar {
font-size: 1rem;
background: #695541 url(../assets/ui/bg_sid_dark.webp) no-repeat right bottom;
background-position: 100%;
color: rgba(220, 220, 220, 0.75);
}
.system-foundryvtt-reve-de-dragon #sidebar .chat-message {
font-size: 1rem;
}
.system-foundryvtt-reve-de-dragon #sidebar-tabs > .collapsed,
.system-foundryvtt-reve-de-dragon #chat-controls .chat-control-icon {
color: rgba(220, 220, 220, 0.75);
@@ -2119,9 +2012,6 @@ select,
font-size: 0.7rem;
flex-grow: 3;
}
.system-foundryvtt-reve-de-dragon .chat-message header.message-header .message-metadata {
flex-grow: 3.5;
}
.system-foundryvtt-reve-de-dragon .chat-message hr {
margin: 0.2rem 0;
}
@@ -2342,7 +2232,7 @@ select,
font-size: 0.8rem;
text-align: center;
vertical-align: middle;
border-radius: 0.2rem;
border-radius: 0.3rem;
}
.system-foundryvtt-reve-de-dragon div.horloge-roue div img {
border: none;
@@ -2669,7 +2559,7 @@ select,
.system-foundryvtt-reve-de-dragon :is(.tooltip, .tooltip-overflow) .ttt-ajustements {
width: 10rem;
background: var(--background-tooltip);
border-radius: 0.5rem;
border-radius: 6px;
font-size: 0.9rem;
padding: 3px 0;
}
@@ -2705,22 +2595,6 @@ select,
border: 2px ridge #846109;
display: inline-block;
}
.system-foundryvtt-reve-de-dragon .chat-card-button img,
.system-foundryvtt-reve-de-dragon .chat-card-button-pushed img {
max-width: 1rem;
max-height: 1rem;
}
.system-foundryvtt-reve-de-dragon .chat-card-info {
font-size: 1.1rem;
display: flex;
flex-direction: row;
}
.system-foundryvtt-reve-de-dragon .chat-card-info img {
margin: 0 0.5rem;
max-width: 1rem;
max-height: 1rem;
filter: invert(0.8);
}
.system-foundryvtt-reve-de-dragon .chat-card-button {
text-shadow: 1px 1px #4d3534;
box-shadow: inset 1x 1px #a6827e;

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.8 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.6 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.6 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.8 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.3 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -66,7 +66,6 @@
"StatusRestrained": "Immobilisé",
"StatusComma": "Comma",
"StatusDead": "Mort",
"StatusDemiReve": "Demi-rêve",
"StatusForceWeak": "Force insuffisante"
"StatusDemiReve": "Demi-rêve"
}
}

View File

@@ -27,11 +27,6 @@
--gradient-red: linear-gradient(150deg, rgba(255, 0, 0, 0.3), rgba(255, 200, 128, 0.05),rgba(255, 200, 128, 0.1), rgba(255,10,0,0.3));
--gradient-violet: linear-gradient(150deg, rgba(100, 45, 124, 0.6), rgba(216, 157, 192, 0.3), rgba(177, 157, 216, 0.5), rgba(107, 62, 121, 0.3), rgba(100, 45, 124, 0.6));
--gradient-purple-black: linear-gradient(150deg, rgba(0, 0, 0, 0.7), rgba(100, 45, 124, 0.4), rgba(82, 17, 131, 0.3),rgba(100, 45, 124, 0.4), rgba(0, 0, 0, 0.7));
--gradient-warning: linear-gradient(150deg,
hsla(32, 100%, 50%, 0.3),
hsla(52, 60%, 50%, 0.1),
hsla(32, 60%, 50%, 0.1),
hsla(32, 100%, 50%, 0.3));
--gradient-silver-light: linear-gradient(30deg, rgba(61, 55, 93, 0.2), rgba(178, 179, 196, 0.1), rgba(59, 62, 63, 0.2), rgba(206, 204, 199, 0.1), rgba(61, 46, 49, 0.2));
--gradient-daylight: conic-gradient(
from 0deg,

View File

@@ -7,7 +7,6 @@
@import "item/munition.less";
@import "item/tarot.less";
@import "roll-dialog.less";
@import "roll-chat.less";
.window-header{
background: rgba(0,0,0,0.75);
}
@@ -334,18 +333,16 @@
flex-shrink: 0;
}
.flex-grow, .flex-grow-3 {
display: flex;
flex-grow: 3;
}
.flex-grow-0-5 {
flex-grow: 0.5;
.flex-grow-2 {
flex-grow: 2;
}
.flex-grow-1 {
flex-grow: 1;
}
.flex-grow-2 {
display: flex;
flex-grow: 2;
.flex-grow-0-5 {
flex-grow: 0.5;
}
.voyage-liste-survies {
max-width: 12rem;
@@ -389,16 +386,14 @@
justify-content: center;
text-align: center;
}
:is(.item-actions-controls, .equipement-actions) {
.item-actions-controls,
.equipement-actions {
margin: 0;
flex-grow: 1.2;
flex-grow: 2;
align-items: end;
justify-content: flex-end;
text-align: right;
}
.liste-equipement :is(.equipement-actions, .item-actions-controls) {
flex-grow: 2;
}
.blessure-control {
flex-grow: 1;
@@ -627,6 +622,16 @@
}
}
}
.flex-grow-1 {
flex-grow: 1;
}
.flex-grow-2 {
flex-grow: 2;
}
.flex-grow-3 {
flex-grow: 3;
}
fieldset {
border-style: groove;
border-width: 0.1rem;
@@ -777,31 +782,31 @@
}
.rdd-roll-part {
align-items: center;
border-radius: 0.5rem; padding: 3px;
border-radius: 6px; padding: 3px;
background: var(--gradient-gold);
}
.rdd-roll-sign{
border-radius: 0.5rem; padding: 3px;
border-radius: 6px; padding: 3px;
background: var(--gradient-silver);
}
.rdd-roll-norm{
border-radius: 0.5rem; padding: 3px;
border-radius: 6px; padding: 3px;
background: var(--gradient-green);
}
.rdd-roll-notSign, .rdd-roll-echec{
border-radius: 0.5rem; padding: 3px;
border-radius: 6px; padding: 3px;
background: var(--gradient-red);
}
.rdd-roll-epart{
border-radius: 0.5rem; padding: 3px;
border-radius: 6px; padding: 3px;
background: var(--gradient-violet);
}
.rdd-roll-etotal{
border-radius: 0.5rem; padding: 3px;
border-radius: 6px; padding: 3px;
background: var(--gradient-purple-black);
}
.rdd-diviseur{
border-radius: 0.5rem; padding: 3px;
border-radius: 6px; padding: 3px;
background: var(--gradient-red);
}
@@ -832,10 +837,15 @@
font-size: 0.8rem;
font-style: italic;
color: rgba(82, 17, 131, 0.9);
overflow-y: scroll;
width: 100%;
overflow: hidden;
}
.poesie-extrait:hover {
max-height: unset;
overflow: visible;
opacity: 1;
}
.poesie-reference {
font-size: 0.7rem;
text-align: right;
@@ -908,7 +918,7 @@
height: var(--form-field-height);
margin: 0;
color: var(--color-text-dark-primary);
border-radius: 0.2rem;
border-radius: 3px;
}
.app-calendar-astrologie{
div.theme-astral{
@@ -965,7 +975,7 @@
background: hsla(280, 50%, 50%, 0.1);
padding: 1px 4px;
border: 1px solid var(--color-border-dark-tertiary);
border-radius: 0.2rem;
border-radius: 2px;
white-space: nowrap;
word-break: break-all;
}
@@ -976,7 +986,7 @@
font-weight: 560;
padding: 0.1rem 0.3rem;
border: 1px solid var(--color-border-dark-tertiary);
border-radius: 0.2rem;
border-radius: 0.25rem;
white-space: nowrap;
word-break: break-all;
display: ruby;
@@ -1106,7 +1116,7 @@
.xp-level-up {
margin: 0.1rem;
box-shadow: inset 0px 0px 1px #00000096;
border-radius: 0.2rem;
border-radius: 0.25rem;
padding: 0.1rem;
flex: 1 1 5rem;
background: var(--gradient-gold) !important;
@@ -1137,7 +1147,7 @@
.list-item {
margin: 0.1rem;
box-shadow: inset 0px 0px 1px #00000096;
border-radius: 0.2rem;
border-radius: 0.25rem;
padding: 0.1rem;
flex: 1 1 1.5rem;
display: flex;
@@ -1314,13 +1324,13 @@
justify-content: flex-start;
flex-direction: column;
position: absolute;
top: 10rem;
left: -9rem;
top: 4.6rem;
left: -19rem;
}
.token-hud-ext.soins {
flex-direction: column;
position: absolute;
top: 15.5rem;
top: 14.7rem;
left: -6rem;
max-width: 8rem;
line-height: 1rem;
@@ -1336,18 +1346,14 @@
width: 9rem;
height: fit-content;
border-radius: 0.3rem;
min-width: 8rem;
min-width: 6rem;
flex-basis: auto;
padding: 0;
line-height: 1.6rem;
line-height: 0.95rem;
margin: 0.2rem;
display: flex;
flex-direction: row;
align-items: center;
select, label {
font-size: 1rem;
}
}
.rdd-hud-menu label {
font-size: 0.8rem;
}
/* ======================================== */
.item-checkbox {
@@ -1445,9 +1451,7 @@
/* ======================================== */
/* Sidebar CSS */
#sidebar {
.chat-message{
font-size: 1rem;
}
font-size: 1rem;
background: rgb(105,85,65) url(../assets/ui/bg_sid_dark.webp) no-repeat right bottom;
background-position: 100%;
color: rgba(220,220,220,0.75);
@@ -1478,15 +1482,10 @@
.message-content {
text-align: justify;
}
header.message-header{
.heure-rdd {
font-size: 0.7rem;
flex-grow: 3;
}
.message-metadata {
flex-grow: 3.5;
}
}
header.message-header .heure-rdd {
font-size: 0.7rem;
flex-grow: 3;
}
hr {
margin: 0.2rem 0;
}
@@ -1685,7 +1684,7 @@
font-size: 0.8rem;
text-align: center;
vertical-align: middle;
border-radius: 0.2rem;
border-radius: 0.3rem;
}
div.horloge-roue div img {
@@ -1921,7 +1920,7 @@
.ttt-ajustements {
width: 10rem;
background: var(--background-tooltip);
border-radius: 0.5rem;
border-radius: 6px;
font-size: 0.9rem;
padding: 3px 0;
div:nth-child(odd) {
@@ -1962,23 +1961,7 @@
border: 2px ridge #846109;
display: inline-block;
img {
max-width: 1rem;
max-height: 1rem;
}
}
.chat-card-info{
font-size: 1.1rem;
display: flex;
flex-direction: row;
img {
margin: 0 0.5rem;
max-width: 1rem;
max-height: 1rem;
filter: invert(0.8);
}
}
.chat-card-button{
text-shadow: 1px 1px #4d3534;

View File

@@ -1,86 +0,0 @@
.chat-message div.roll-chat,
.dialog-content div.roll-chat {
font-family: CaslonAntique;
display: grid;
grid-template-areas:
"img header buttons"
"img resume buttons"
"details details details"
"actions actions actions";
grid-template-columns: 3rem 1fr 1.4rem;
grid-template-rows: max-content max-content max-content max-content;
gap: 0 0.5rem;
div.chat-img {
grid-area: img;
display: flex;
flex-direction: column;
img {
border: 0;
max-height: 3rem;
max-width: 3rem;
object-fit: contain;
height: 100%;
}
}
div.chat-header {
grid-area: header;
font-weight: bold;
font-size: 0.9rem;
}
div.chat-resume {
grid-area: resume;
text-align: justify;
}
div.chat-details {
grid-area: details;
text-align: justify;
display: flex;
flex-direction: column;
}
div.chat-actions {
grid-area: actions;
display: flex;
flex-direction: column;
a {
display: flex;
flex-direction: row;
img {
margin-right: 0.5rem;
}
}
}
div.chat-buttons {
grid-area: buttons;
display: flex;
flex-direction: column;
a {
border-radius: 0.2rem;
cursor: pointer;
padding: 0.2rem;
position: relative;
box-shadow: inset 1x 1px #a6827e;
color: var(--color-controls);
border: 1px ridge #846109;
display: inline-block;
align-items: center;
img {
max-width: 1rem;
max-height: 1rem;
}
}
a:hover {
background: var(--background-custom-button-hover);
}
a:active{
position:relative;
top:1px;
}
}
}

View File

@@ -4,11 +4,11 @@
grid-template-areas:
"header header header header header header header"
"action action action action action action action"
"type separation separation separation separation separation separation"
"type carac carac carac comp comp resume"
"type choix choix choix choix choix conditions"
"type resolution resolution resolution resolution resolution conditions"
"type chances chances chances chances chances buttons"
"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;
@@ -22,18 +22,18 @@
roll-choix { grid-area: choix; }
roll-table { grid-area: resolution; }
roll-conditions { grid-area: conditions; }
roll-conditions { grid-area: modifiers; }
roll-chances { grid-area: chances; }
roll-resume { grid-area: resume; }
roll-buttons { grid-area: buttons; }
roll-type {
grid-area: type;
roll-mode {
grid-area: mode;
display: flex;
flex-direction: column;
}
roll-conditions roll-section[name="rollmode"],
roll-type {
roll-mode {
button[data-checked="true"] {
background-color: var(--color-text-selection-bg);
color: var(--color-controls);
@@ -89,17 +89,13 @@
display: flex;
flex-direction: row;
margin: 0.1rem 0;
.warning {
border-radius: 0.5rem;
background: var(--gradient-warning);
}
}
roll-part-img {
display: flex;
flex-direction: column;
grid-area: img;
img {
img{
border: 0;
padding: 1px;
max-height: 3rem;
@@ -121,18 +117,6 @@
div.poesie-extrait{
display: flex;
flex-direction: column;
align-items: normal;
}
span.status-surprise{
display: flex;
flex-direction: row;
flex-flow: wrap;
img {
filter: invert(0.8);
}
}
label {
align-content: center;
}
}
}
@@ -142,13 +126,8 @@
display: flow;
width: 2.5rem;
text-align: right;
margin: 0 0.2rem;
margin: 0 0.2rem 0 0.5rem;
padding: 0 0.2rem;
border: 1px solid ;
border-radius: 0.2rem ;
background: hsla(0, 0%, 0%, 0.2);
height: 1.5rem;
background: hsla(0, 0%, 0%, 0.2);
}
roll-action {
@@ -211,14 +190,14 @@
}
roll-carac select[name="select-carac"] {
min-width: 6.5rem;
max-width: 8rem;
}
max-width: 6rem;
}
roll-comp select[name="select-comp"] {
min-width: 8rem;
max-width: 10rem;
margin-left: 1.5rem;
}
max-width: 11rem;
margin-left: 1rem;
}
roll-conditions roll-section[name="coeur"] select[name="coeur"] {
max-width: 4rem;

View File

@@ -8,7 +8,7 @@
min-height: 100px; // Hauteur minimale pour la description
background: var(--rdd-bg-input-alt); // Une couleur de fond alternative
padding: 5px;
border-radius: 0.2rem;
border-radius: 3px;
color: var(--rdd-color-text-primary);
}
@@ -28,7 +28,7 @@
background: var(--fieldset-background);
color: var(--rdd-color-text-primary);
margin-bottom: 4px;
border-radius: 0.5rem;
border-radius: 6px;
border-color: var(--rdd-color-text-primary);
border-width: 2px;
}
@@ -64,7 +64,7 @@
--rdd-color-text-input
); // Assurez-vous que cette variable existe
padding: 2px 2px; // Augmentation du padding vertical
border-radius: 0.2rem;
border-radius: 3px;
}
input[type="checkbox"] {

View File

@@ -1,4 +1,4 @@
import { renderTemplate, SYSTEM_RDD } from "../constants.js";
import { SYSTEM_RDD } from "../constants.js";
import { RdDUtility } from "../rdd-utility.js";
const DETAIL_VENTE = 'detailVente';

View File

@@ -1,4 +1,3 @@
import { renderTemplate } from "../constants.js";
import { Misc } from "../misc.js";
import { RdDUtility } from "../rdd-utility.js";
import { ChatVente } from "./chat-vente.js";

View File

@@ -1,4 +1,3 @@
import { renderTemplate } from "../constants.js";
import { HtmlUtility } from "../html-utility.js";
import { RdDUtility } from "../rdd-utility.js";
import { ChatVente } from "./chat-vente.js";

View File

@@ -3,7 +3,7 @@ import { HtmlUtility } from "./html-utility.js";
import { RdDBonus } from "./rdd-bonus.js";
import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js";
import { CARACS, RdDCarac } from "./rdd-carac.js";
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";
@@ -11,6 +11,7 @@ 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";
@@ -48,7 +49,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
});
foundry.utils.mergeObject(formData.calc, {
surenc: this.actor.computeMalusSurEncombrement(),
surprise: RdDBonus.find(this.actor.getSurprise(false)).label,
surprise: RdDBonus.find(this.actor.getSurprise(false)).descr,
resumeBlessures: this.actor.computeResumeBlessure(this.actor.system.blessures),
caracTotal: RdDCarac.computeTotal(this.actor.system.carac, this.actor.system.beaute),
surEncombrementMessage: this.actor.isSurenc() ? "Sur-Encombrement!" : "",
@@ -174,7 +175,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
await this.getBlessure(event)?.setSoinsBlessure({ soinscomplets: { bonus: Number(event.currentTarget.value) } })
});
this.html.find('.roll-chance-actuelle').click(async event => await this.actor.rollCarac(CARACS.CHANCE_ACTUELLE))
this.html.find('.roll-chance-actuelle').click(async event => await this.actor.rollCarac('chance-actuelle'))
this.html.find('.button-appel-chance').click(async event => await this.actor.rollAppelChance())
this.html.find('[name="jet-astrologie"]').click(async event => await this.actor.astrologieNombresAstraux())
@@ -208,7 +209,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
}
// Points de reve actuel
this.html.find('.roll-reve-actuel').click(async event => await this.actor.rollCarac(CARACS.REVE_ACTUEL, { resistance: true }))
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 => {

View File

@@ -1,10 +1,7 @@
/**
* class providing the actor and token, and choosing the name and image from the token if available.
*/
export class TokenActor {
static fromTokenActor(token, actor){
return token ? TokenActor.fromToken(token) : TokenActor.fromActor(actor)
}
export class ActorToken {
static fromActorId(actorId, onError = () => undefined) {
actorId = actorId ?? (canvas.tokens.controlled.length > 0
@@ -19,22 +16,22 @@ export class TokenActor {
static fromActor(actor) {
const token = actor.isToken ? actor.token : actor.prototypeToken
return TokenActor.fromToken(token)
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 TokenActor.fromToken(token)
return ActorToken.fromToken(token)
}
static fromToken(token) {
return new TokenActor(token)
return new ActorToken(token)
}
constructor(token) {
this.name = token.name ?? token.actor.name
this.img = token.actor.isToken && token.texture.src ? token.texture.src : token.actor.img
this.img = token.texture.src ?? token.actor.img
this.actor = token.actor
this.id = token.actor?.id
this.token = token

View File

@@ -14,12 +14,12 @@ import { STATUSES } from "./settings/status-effects.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
import { Draconique } from "./tmr/draconique.js";
import { CARACS, LIST_CARAC_PERSONNAGE, RdDCarac } from "./rdd-carac.js";
import { LIST_CARAC_PERSONNAGE, RdDCarac } from "./rdd-carac.js";
import { DialogConsommer } from "./dialog-item-consommer.js";
import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js";
import { RollDataAjustements } from "./rolldata-ajustements-v1.js";
import { RollDataAjustements } from "./rolldata-ajustements.js";
import { RdDPossession } from "./rdd-possession.js";
import { ACTOR_TYPES, renderTemplate, 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 { DialogRepos } from "./sommeil/dialog-repos.js";
import { RdDBaseActor } from "./actor/base-actor.js";
@@ -31,8 +31,9 @@ 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 { RdDCombatManager } from "./rdd-combat.js";
import { ATTAQUE_TYPE, RdDItemArme } from "./item/arme.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";
@@ -46,12 +47,7 @@ import { PAS_DE_DRACONIC, POSSESSION_SANS_DRACONIC } from "./item/base-items.js"
import { RdDRollResult } from "./rdd-roll-result.js";
import { RdDInitiative } from "./initiative.mjs";
import RollDialog from "./roll/roll-dialog.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js";
import { ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION } from "./roll/roll-constants.mjs";
import { PART_TACHE } from "./roll/roll-part-tache.mjs";
import { PART_COMP } from "./roll/roll-part-comp.mjs";
import { PART_OEUVRE } from "./roll/roll-part-oeuvre.mjs";
import { PART_CUISINE } from "./roll/roll-part-cuisine.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js";
export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre']
@@ -103,8 +99,6 @@ export class RdDActor extends RdDBaseActorSang {
}
isPersonnage() { return true }
isFeminin() { return this.system.sexe.length > 0 && this.system.sexe.charAt(0).toLowerCase() == 'f' }
isHautRevant() { return this.system.attributs.hautrevant.value != "" }
/* -------------------------------------------- */
@@ -143,12 +137,12 @@ export class RdDActor extends RdDBaseActorSang {
}
listActions({ isAttaque = false, isEquipe = false }) {
// Recupération des attaques
// Recupération des armes
const actions = this.listActionsAttaque()
.filter(it => !isEquipe || it.arme.system.equipe)
if (!isAttaque && this.system.attributs.hautrevant.value) {
actions.push({ label: "Draconic", action: 'haut-reve', initOnly: true })
actions.push({ name: "Draconic", action: 'haut-reve', initOnly: true })
}
return actions
}
@@ -165,72 +159,71 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
getDemiReve() { return this.system.reve.tmrpos.coord }
getDraconics() { return this.itemTypes[ITEM_TYPES.competence].filter(it => it.system.categorie == 'draconic') }
getBestDraconic() { return foundry.utils.duplicate([...this.getDraconics(), PAS_DE_DRACONIC].sort(Misc.descending(it => it.system.niveau)).find(it => true)) }
getDraconicList() { return this.itemTypes[ITEM_TYPES.competence].filter(it => it.system.categorie == 'draconic') }
getBestDraconic() { return foundry.utils.duplicate([...this.getDraconicList(), PAS_DE_DRACONIC].sort(Misc.descending(it => it.system.niveau)).find(it => true)) }
getDraconicOuPossession() {
return [...this.getDraconics().filter(it => it.system.niveau >= 0), POSSESSION_SANS_DRACONIC]
return [...this.getDraconicList().filter(it => it.system.niveau >= 0), POSSESSION_SANS_DRACONIC]
.sort(Misc.descending(it => it.system.niveau))
.find(it => true)
}
isForceInsuffisante(forceRequise) {
const force = parseInt(this.system.carac.force.value)
return forceRequise > force
}
/* -------------------------------------------- */
/** Retourne une liste triée d'actions d'armes avec le split arme1 main / arme 2 main / lancer */
listActionsAttaque() {
const actions = []
const uniques = []
let actions = [
this.$prepareAttaqueArme(RdDItemArme.empoignade(this)),
this.$prepareAttaqueArme(RdDItemArme.corpsACorps(this)),
]
const addAttaque = (arme, main = undefined, action = 'attaque') => {
const dommagesArme = RdDItemArme.valeurMain(arme.system.dommages, main)
const forceRequise = RdDItemArme.valeurMain(arme.system.force ?? 0, main)
const ecaillesEfficacite = arme.system.magique ? arme.system.ecaille_efficacite : 0;
const armes = this.itemTypes[ITEM_TYPES.arme]
.filter(it => RdDItemArme.isAttaque(it))
.sort(Misc.ascending(it => it.name));
const comp = this.getCompetence(RdDActor.$getCompetenceAction(arme, main))
const unique = [comp.id, arme.name, dommagesArme, forceRequise, ecaillesEfficacite].join('|');
if (uniques.includes(unique)) {
return
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)'))
}
uniques.push(unique);
const caracCode = RdDActor.$getCaracAction(comp, main)
const caracValue = this.system.carac[caracCode].value
const niveau = comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(main) ? -8 : -6)
const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + ecaillesEfficacite
actions.push({
label: arme.name + (main ? ' ' + main : ''),
action: 'attaque',
initOnly: false,
arme: arme,
comp: comp,
main: main,
carac: { key: caracCode, value: caracValue },
equipe: arme.system.equipe,
dommagesArme: dommagesArme,
forceRequise: forceRequise,
initiative: RdDInitiative.getRollInitiative(caracValue, niveau, ajustement)
})
}
return actions;
}
this.itemTypes[ITEM_TYPES.arme]
.filter(it => it.isAttaque())
.sort(Misc.ascending(it => it.name))
.forEach(arme => {
if (arme.system.unemain && arme.system.competence && arme.system.resistance > 0) { addAttaque(arme, ATTAQUE_TYPE.UNE_MAIN) }
if (arme.system.deuxmains && arme.system.competence && arme.system.resistance > 0) { addAttaque(arme, ATTAQUE_TYPE.DEUX_MAINS) }
if (arme.system.lancer && arme.system.resistance > 0) { addAttaque(arme, ATTAQUE_TYPE.LANCER) }
if (arme.system.tir) { addAttaque(arme, ATTAQUE_TYPE.TIR) }
})
/* -------------------------------------------- */
$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()
addAttaque(RdDItemArme.pugilat(this), ATTAQUE_TYPE.CORPS_A_CORPS)
addAttaque(RdDItemArme.empoignade(this), ATTAQUE_TYPE.CORPS_A_CORPS, 'empoignade')
// 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 dommagesArme = parseInt(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 actions
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,
dommagesArme: dommagesArme,
initiative: RdDInitiative.calculInitiative(niveau, caracValue, ajustement)
}
}
static $getCaracAction(comp, main) {
@@ -246,10 +239,10 @@ export class RdDActor extends RdDBaseActorSang {
static $getCompetenceAction(arme, main) {
switch (main) {
case ATTAQUE_TYPE.UNE_MAIN: return arme.competence1Mains()
case ATTAQUE_TYPE.DEUX_MAINS: return arme.competence2Mains()
case ATTAQUE_TYPE.LANCER: return arme.system.lancer
case ATTAQUE_TYPE.TIR: return arme.system.tir
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
}
}
@@ -514,7 +507,7 @@ export class RdDActor extends RdDBaseActorSang {
'system.sante.fatigue.value': 0,
'system.compteurs.ethylisme': { value: 1, nb_doses: 0, jet_moral: false }
})
await this.removeEffects(e => !e.statuses?.has(STATUSES.StatusDemiReve));
await this.removeEffects(e => e.id != STATUSES.StatusDemiReve);
await this.supprimerBlessures(it => true);
await ChatMessage.create({
whisper: ChatUtility.getOwners(this),
@@ -705,12 +698,11 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async combattreReveDeDragon(force) {
const rencontre = await game.system.rdd.rencontresTMR.getReveDeDragon(force);
let rollData = {
actor: this,
competence: this.getDraconicOuPossession(),
canClose: false,
rencontre: rencontre,
rencontre: await game.system.rdd.rencontresTMR.getReveDeDragon(force),
tmr: true,
use: { libre: false, conditions: false },
forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: this.getReveActuel() } }
@@ -1351,7 +1343,7 @@ export class RdDActor extends RdDBaseActorSang {
async _apprecierCuisine(item, seForcer) {
const surmonteExotisme = await this._surmonterExotisme(item, seForcer);
if (surmonteExotisme) {
await this.apprecier(CARACS.ODORATGOUT, 'cuisine', item.system.qualite, item.system.boisson ? "apprécie la boisson" : "apprécie le plat");
await this.apprecier('gout', 'cuisine', item.system.qualite, item.system.boisson ? "apprécie la boisson" : "apprécie le plat");
}
else if (seForcer) {
await this.jetDeMoral('malheureux');
@@ -1369,7 +1361,7 @@ export class RdDActor extends RdDBaseActorSang {
if (exotisme < 0 || qualite < 0) {
const competence = qualite > 0 ? 'cuisine' : undefined
const difficulte = Math.min(exotisme, qualite)
const rolled = await this.doRollCaracCompetence(CARACS.VOLONTE, competence, difficulte, { title: `tente de surmonter l'exotisme de ${item.name}` })
const rolled = await this.doRollCaracCompetence('volonte', competence, difficulte, { title: `tente de surmonter l'exotisme de ${item.name}` })
return rolled.isSuccess
}
return true;
@@ -1691,7 +1683,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
computeDraconicAndSortIndex(sortList) {
let draconicList = this.getDraconics();
let draconicList = this.getDraconicList();
for (let sort of sortList) {
let draconicsSort = RdDItemSort.getDraconicsSort(draconicList, sort).map(it => it.name);
for (let index = 0; index < draconicList.length && sort.system.listIndex == undefined; index++) {
@@ -1931,21 +1923,6 @@ export class RdDActor extends RdDBaseActorSang {
}
async rollCaracCompetence(caracName, compName, diff, options = { title: "" }) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: { allowed: [PART_COMP], current: PART_COMP },
selected: {
carac: { key: caracName },
comp: { key: compName, forced: options.forced },
diff: { value: diff ?? 0 }
}
}
RollDialog.create(rollData, foundry.utils.mergeObject(options, { onRollDone: RollDialog.onRollDoneClose }))
return
}
RdDEmpoignade.checkEmpoignadeEnCours(this)
const competence = this.getCompetence(compName);
await this.openRollDialog({
@@ -1968,34 +1945,23 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async rollTache(id, options = {}) {
RdDEmpoignade.checkEmpoignadeEnCours(this)
const tache = this.getTache(id)
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
selected: { tache: { key: tache.id, forced: options.forced } },
type: { allowed: [PART_TACHE], current: PART_TACHE }
}
RollDialog.create(rollData, options)
return
}
const compData = this.getCompetence(tache.system.competence)
compData.system.defaut_carac = tache.system.carac; // Patch !
const tacheData = this.getTache(id)
const compData = this.getCompetence(tacheData.system.competence)
compData.system.defaut_carac = tacheData.system.carac; // Patch !
await this.openRollDialog({
name: 'jet-competence',
label: 'Jet de Tâche ' + tache.name,
label: 'Jet de Tâche ' + tacheData.name,
template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.hbs',
rollData: {
competence: compData,
tache: tache,
diffLibre: tache.system.difficulte,
tache: tacheData,
diffLibre: tacheData.system.difficulte,
diffConditions: 0,
use: { libre: false, conditions: true },
carac: {
[tache.system.carac]: foundry.utils.duplicate(this.system.carac[tache.system.carac])
[tacheData.system.carac]: foundry.utils.duplicate(this.system.carac[tacheData.system.carac])
}
},
callbacks: [{ action: r => this._tacheResult(r, options) }]
@@ -2029,19 +1995,9 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async rollJeu(id) {
const jeu = this.getJeu(id);
const oeuvre = this.getJeu(id);
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
selected: { jeu: { key: jeu.id } },
type: { allowed: [ROLL_TYPE_JEU], current: ROLL_TYPE_JEU }
}
await RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose })
return
}
const listCarac = jeu.system.caraccomp.toLowerCase().split(/[.,:\/-]/).map(it => it.trim());
const listCarac = oeuvre.system.caraccomp.toLowerCase().split(/[.,:\/-]/).map(it => it.trim());
const carac = listCarac.length > 0 ? listCarac[0] : 'chance'
const artData = {
art: 'jeu', verbe: 'Jeu',
@@ -2051,25 +2007,14 @@ 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, jeu.system.base);
await this._rollArtV1(artData, carac, jeu);
artData.competence.system.niveau = Math.max(artData.competence.system.niveau, oeuvre.system.base);
await this._rollArtV1(artData, carac, oeuvre);
}
/* -------------------------------------------- */
async rollMeditation(id) {
const meditation = foundry.utils.duplicate(this.getMeditation(id));
if (meditation && OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
selected: { meditation: { key: id } },
type: { allowed: [ROLL_TYPE_MEDITATION], current: ROLL_TYPE_MEDITATION }
}
await RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose })
return
}
const competence = foundry.utils.duplicate(this.getCompetence(meditation.system.competence));
competence.system.defaut_carac = "intellect"; // Meditation = toujours avec intellect
let meditationData = {
@@ -2128,7 +2073,7 @@ export class RdDActor extends RdDBaseActorSang {
ui.notifications.info(`Aucun signe draconiques en ${coord} !`);
return;
}
let draconicList = this.getDraconics()
let draconicList = this.getDraconicList()
.map(draconic => {
let draconicLecture = foundry.utils.duplicate(draconic);
draconicLecture.system.defaut_carac = "intellect";
@@ -2333,12 +2278,13 @@ export class RdDActor extends RdDBaseActorSang {
static _getComposantsCaracDerivee(caracName) {
switch (Grammar.toLowerCaseNoAccent(caracName)) {
case CARACS.REVE_ACTUEL: case 'reve actuel': return [CARACS.REVE]
case CARACS.CHANCE_ACTUELLE: case 'chance actuelle': return [CARACS.CHANCE]
case CARACS.TIR: return [CARACS.DEXTERITE, CARACS.VUE]
case CARACS.LANCER: return [CARACS.FORCE, CARACS.DEXTERITE, CARACS.VUE]
case CARACS.MELEE: return [CARACS.FORCE, CARACS.AGILITE]
case CARACS.DEROBEE: return [CARACS.AGILITE]
case 'reve-actuel': case 'reve actuel': return ['reve']
case 'chance-actuelle': case 'chance actuelle': return ['chance']
case 'vie': return ['constitution']
case 'tir': return ['vue', 'dexterite']
case 'lancer': return ['force', 'dexterite', 'vue']
case 'melee': return ['force', 'agilite']
case 'derobee': return ['agilite']
}
return []
}
@@ -2409,7 +2355,7 @@ export class RdDActor extends RdDBaseActorSang {
return
}
if (mode != 'visu' && this.isDemiReve()) {
ui.notifications.warn("Le personnage est déjà dans les Terres Médianes, elles s'affichent en visualisation")
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
}
if (mode == 'visu') {
@@ -2448,7 +2394,7 @@ export class RdDActor extends RdDBaseActorSang {
let tmrFormData = {
mode: mode,
fatigue: RdDUtility.calculFatigueHtml(fatigue, endurance),
draconic: this.getDraconics(),
draconic: this.getDraconicList(),
sort: this.itemTypes['sort'],
signes: this.itemTypes['signedraconique'],
caracReve: parseInt(this.system.carac.reve.value),
@@ -2470,17 +2416,14 @@ export class RdDActor extends RdDBaseActorSang {
if (!blessure.system.premierssoins.done) {
const tache = await this.getTacheBlessure(blesse, blessure);
return await this.rollTache(tache.id, {
onRollAutomate: async r => blesse.onRollTachePremiersSoins(blessureId, r),
title: 'Premiers soins',
forced: true
onRollAutomate: async r => blesse.onRollTachePremiersSoins(blessureId, r)
});
}
else if (!blessure.system.soinscomplets.done) {
if (!blessure.system.soinscomplets.done) {
const diff = blessure.system.difficulte + (blessure.system.premierssoins.bonus ?? 0);
return await this.rollCaracCompetence(CARACS.DEXTERITE, "Chirurgie", diff, {
return await this.rollCaracCompetence("dexterite", "Chirurgie", diff, {
title: "Soins complets",
onRollAutomate: r => blesse.onRollSoinsComplets(blessureId, r),
forced: true
onRollAutomate: r => blesse.onRollSoinsComplets(blessureId, r)
})
}
}
@@ -2495,7 +2438,6 @@ export class RdDActor extends RdDBaseActorSang {
})
}
const blessure = this.getItem(blessureId, 'blessure')
if (blessure && !blessure.system.premierssoins.done) {
const tache = rollData.tache;
if (rollData.rolled.isETotal) {
@@ -2573,27 +2515,29 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
async computeArmure(dmg) {
let baseDmg = (dmg.dmgArme ?? 0) + (dmg.dmgActor ?? 0);
async computeArmure(attackerRoll) {
let dmg = (attackerRoll.dmg.dmgArme ?? 0) + (attackerRoll.dmg.dmgActor ?? 0);
let armeData = attackerRoll.arme;
let protection = 0;
if (dmg.encaisserSpecial != "noarmure") {
const armures = this.items.filter(it => it.type == "armure" && it.system.equipe)
for (const armure of armures) {
protection += await RdDDice.rollTotal(armure.system.protection.toString());
if (baseDmg > 0 && dmg.encaisserSpecial != "noarmure") {
await armure.deteriorerArmure(baseDmg)
baseDmg = 0;
}
}
protection -= Math.min(dmg.penetration, protection)
protection += this.getProtectionNaturelle();
// Gestion des cas particuliers sur la fenêtre d'encaissement
if (dmg.encaisserSpecial == "chute") {
protection = Math.min(protection, 2);
const armures = this.items.filter(it => it.type == "armure" && it.system.equipe);
for (const armure of armures) {
protection += await RdDDice.rollTotal(armure.system.protection.toString());
if (dmg > 0 && attackerRoll.dmg.encaisserSpecial != "noarmure") {
await armure.deteriorerArmure(dmg)
dmg = 0;
}
}
console.log("Final protect", protection, dmg)
const penetration = Misc.toInt(armeData?.system.penetration ?? 0);
protection = Math.max(protection - penetration, 0);
protection += this.getProtectionNaturelle();
// Gestion des cas particuliers sur la fenêtre d'encaissement
if (attackerRoll.dmg.encaisserSpecial == "noarmure") {
protection = 0;
}
if (attackerRoll.dmg.encaisserSpecial == "chute") {
protection = Math.min(protection, 2);
}
console.log("Final protect", protection, attackerRoll);
return protection;
}
@@ -2976,9 +2920,7 @@ export class RdDActor extends RdDBaseActorSang {
break
case ITEM_TYPES.race:
await this.onCreateOwnedRace(item, options, id)
break
}
await super.onCreateItem(item, options, id)
await item.onCreateItemTemporel(this);
await item.onCreateDecoupeComestible(this);
}
@@ -3109,17 +3051,40 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async _rollArtV2(oeuvreId) {
async _rollArtV2(oeuvreId, callbackAction = async (actor, rd) => await actor._resultArtV2(rd)) {
const oeuvre = this.items.get(oeuvreId)
const rollData = {
ids: { actorId: this.id },
selected: { oeuvre: { key: oeuvre.id } },
type: { allowed: [PART_OEUVRE], current: PART_OEUVRE, },
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, { onRollDone: RollDialog.onRollDoneClose })
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)
@@ -3205,40 +3170,28 @@ export class RdDActor extends RdDBaseActorSang {
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
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite;
await RdDRollResult.displayRollData(artData, this.name, `chat-resultat-${artData.art}.hbs`);
}
/* -------------------------------------------- */
async rollRecetteCuisine(id) {
const recette = this.getRecetteCuisine(id);
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: { allowed: [PART_CUISINE], current: PART_CUISINE },
selected: {
cuisine: { key: recette.id }
}
}
RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose })
return
}
const oeuvre = this.getRecetteCuisine(id);
const artData = {
verbe: 'Cuisiner',
compName: 'cuisine',
proportions: 1,
ajouterEquipement: false
};
await this._rollArtV1(artData, 'odoratgout', recette, r => this._resultRecetteCuisine(r));
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.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 = {
@@ -3264,18 +3217,6 @@ export class RdDActor extends RdDBaseActorSang {
}
async preparerNourriture(item) {
if (item.getUtilisationCuisine() == 'brut' && OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: { allowed: [PART_CUISINE], current: PART_CUISINE },
selected: {
cuisine: { key: item.id }
}
}
RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose })
return
}
if (item.getUtilisationCuisine() == 'brut') {
const nourriture = {
name: 'Plat de ' + item.name,
@@ -3286,7 +3227,7 @@ export class RdDActor extends RdDBaseActorSang {
exotisme: item.system.exotisme,
ingredients: item.name
}
}
};
const artData = {
verbe: 'Préparer',
compName: 'cuisine',
@@ -3308,4 +3249,3 @@ export class RdDActor extends RdDBaseActorSang {
}
}

View File

@@ -1,4 +1,4 @@
import { ENTITE_INCARNE, renderTemplate, SHOW_DICE, SYSTEM_RDD } from "../constants.js";
import { ENTITE_INCARNE, SHOW_DICE, SYSTEM_RDD } from "../constants.js";
import { Grammar } from "../grammar.js";
import { Misc } from "../misc.js";
import { RdDResolutionTable } from "../rdd-resolution-table.js";
@@ -11,11 +11,12 @@ import { ITEM_TYPES } from "../constants.js";
import { StatusEffects, STATUSES } from "../settings/status-effects.js";
import { Targets } from "../targets.js";
import { RdDConfirm } from "../rdd-confirm.js";
import { CARACS, RdDCarac } from "../rdd-carac.js";
import { RdDCarac } from "../rdd-carac.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 { RdDItemArme } from "../item/arme.js";
import { ChatUtility } from "../chat-utility.js";
import { DialogValidationEncaissement } from "../dialog-validation-encaissement.js";
@@ -23,12 +24,7 @@ import { RdDCombat } from "../rdd-combat.js";
import { RdDEmpoignade } from "../rdd-empoignade.js";
import { RdDPossession } from "../rdd-possession.js";
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, POSSESSION_SANS_DRACONIC } from "../item/base-items.js";
import { RollDataAjustements } from "../rolldata-ajustements-v1.js";
import { MappingCreatureArme } from "../item/mapping-creature-arme.mjs";
import RollDialog from "../roll/roll-dialog.mjs";
import { ATTAQUE_ROLL_TYPES, DEFAULT_ROLL_TYPES, DIFF, ROLL_TYPE_ATTAQUE, ROLL_TYPE_COMP, ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_OEUVRE, ROLL_TYPE_TACHE } from "../roll/roll-constants.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2 } from "../settings/options-avancees.js";
import { PART_COMP } from "../roll/roll-part-comp.mjs";
import { RollDataAjustements } from "../rolldata-ajustements.js";
/**
* Classe de base pour les acteurs disposant de rêve (donc, pas des objets)
@@ -84,7 +80,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
getBonusDegat() { return RdDCarac.getCaracDerivee(this.getEncombrementMax()).plusdom }
getMoralTotal() { return 0 }
listeAmoureux() { return [] }
listeAmoureux() {return []}
getProtectionNaturelle() { return Number(this.system.attributs?.protection?.value ?? 0) }
getSConst() { return 0 }
@@ -117,12 +113,13 @@ export class RdDBaseActorReve extends RdDBaseActor {
listActions({ isAttaque = false, isEquipe = false }) {
return this.itemTypes[ITEM_TYPES.competencecreature]
.filter(it => it.isAttaque())
.map(it => it.attaqueCreature())
.filter(it => RdDItemCompetenceCreature.isAttaque(it))
.map(it => RdDItemCompetenceCreature.attaqueCreature(it))
.filter(it => it != undefined);
}
async computeArmure(dmg) { return this.getProtectionNaturelle() }
async computeArmure(attackerRoll) { return this.getProtectionNaturelle() }
async remiseANeuf() { }
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { }
@@ -194,10 +191,6 @@ export class RdDBaseActorReve extends RdDBaseActor {
return RdDItemArme.getArme(armeParadeId ? this.getEmbeddedDocument('Item', armeParadeId) : undefined)
}
isForceInsuffisante(forceRequise) {
return false
}
getDraconicOuPossession() { return POSSESSION_SANS_DRACONIC }
getPossession(possessionId) {
@@ -229,13 +222,8 @@ export class RdDBaseActorReve extends RdDBaseActor {
/* -------------------------------------------- */
isEffectAllowed(effectId) { return false }
getEffects(filter = e => true, forceRequise = undefined) {
const effects = this.getEmbeddedCollection("ActiveEffect")
const selected = effects.filter(filter)
if (forceRequise && this.isForceInsuffisante(forceRequise)) {
selected.push(StatusEffects.prepareActiveEffect(STATUSES.StatusForceWeak))
}
return selected
getEffects(filter = e => true) {
return this.getEmbeddedCollection("ActiveEffect").filter(filter);
}
getEffectByStatus(statusId) {
@@ -260,8 +248,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
async removeEffects(filter = e => true) {
if (game.user.isGM) {
const effectsToRemove = this.getEffects(filter);
const ids = effectsToRemove.map(it => it.id);
const ids = this.getEffects(filter).map(it => it.id);
await this.deleteEmbeddedDocuments('ActiveEffect', ids);
}
}
@@ -272,7 +259,11 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
getSurprise(isCombat = undefined) {
return StatusEffects.getSurprise(this.getEffects(), isCombat)
return StatusEffects.typeSurprise(
this.getEffects()
.map(it => StatusEffects.niveauSurprise(it, isCombat))
.reduce(Misc.sum(), 0)
)
}
/* -------------------------------------------- */
@@ -381,22 +372,9 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
/* -------------------------------------------- */
async rollCarac(caracName, options = {}) {
if (Grammar.equalsInsensitive(caracName, CARACS.TAILLE)) {
if (Grammar.equalsInsensitive(caracName, 'taille')) {
return
}
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: { allowed: [PART_COMP], current: PART_COMP },
selected: {
carac: { key: caracName },
comp: options.resistance ? { key: undefined, forced: true } : undefined
}
}
RollDialog.create(rollData, options)
return
}
foundry.utils.mergeObject(options, { resistance: false, diff: 0 }, { overwrite: false })
RdDEmpoignade.checkEmpoignadeEnCours(this)
let selectedCarac = this.getCaracByName(caracName)
@@ -424,33 +402,9 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
/* -------------------------------------------- */
async rollCompetenceV2(rollData) {
rollData.ids = rollData?.ids ?? {}
rollData.type = rollData.type ?? { allowed: DEFAULT_ROLL_TYPES }
rollData.ids.actorId = this.id
await RollDialog.create(rollData)
}
async rollCompetence(idOrName, options = { tryTarget: true, arme: undefined }) {
RdDEmpoignade.checkEmpoignadeEnCours(this)
const competence = this.getCompetence(idOrName);
if (competence.type != ITEM_TYPES.competencecreature && OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
selected: {
comp: { key: competence.name },
diff: { type: DIFF.LIBRE, value: competence.system.default_diffLibre ?? 0 }
}
}
if (options.arme) {
rollData.selected.attaque = { arme: { id: options.arme.id }, comp: { id: competence.id } }
rollData.type = { allowed: ATTAQUE_ROLL_TYPES }
}
await this.rollCompetenceV2(rollData)
return
}
let rollData = {
carac: this.system.carac,
competence: competence,
@@ -458,7 +412,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
if (competence.type == ITEM_TYPES.competencecreature) {
const token = RdDUtility.getSelectedToken(this)
const arme = MappingCreatureArme.armeCreature(competence)
const arme = RdDItemCompetenceCreature.armeCreature(competence)
if (arme && options.tryTarget && Targets.hasTargets()) {
Targets.selectOneTargetToken(target => {
if (arme.action == "possession") {
@@ -468,10 +422,10 @@ export class RdDBaseActorReve extends RdDBaseActor {
RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme)
}
});
return
return;
}
// Transformer la competence de créature
MappingCreatureArme.setRollDataCreature(rollData)
RdDItemCompetenceCreature.setRollDataCreature(rollData)
}
const dialogLabel = 'Jet ' + Grammar.apostrophe('de', competence.name);
await this.openRollDialog({
@@ -490,56 +444,16 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
}
rollAttaque(token) {
token = token ?? RdDUtility.getSelectedToken(this)
if (Targets.hasTargets()) {
Targets.selectOneTargetToken(target => {
if (Targets.isTargetEntite(target)) {
ui.notifications.warn(`Vous ne pouvez pas attaquer une entité non incarnée!!!!`)
return
}
RdDCombat.rddCombatTarget(target, this, token).attaqueV2();
})
}
else {
return RdDConfirm.confirmer({
settingConfirmer: "confirmer-combat-sans-cible",
content: `<p>Voulez vous faire une attaque sans choisir de cible valide?
<br>Tous les jets de combats devront être gérés à la main
</p>`,
title: 'Ne pas utiliser les automatisation de combat',
buttonLabel: "Pas d'automatisation",
onAction: async () => {
this.rollCompetenceV2({
ids: {
actorId: this.id,
actorTokenId: token?.id,
},
selected: {
conditions: { value: 0 }
},
type: {
allowed: [ROLL_TYPE_COMP, ROLL_TYPE_ATTAQUE, ROLL_TYPE_OEUVRE, ROLL_TYPE_TACHE, ROLL_TYPE_JEU],
current: ROLL_TYPE_COMP
}
})
}
})
}
}
/** --------------------------------------------
* @param {*} arme item d'arme/compétence de créature
* @param {*} categorieArme catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession
* @returns
* @returns
*/
rollArme(arme, categorieArme = 'competence', token = undefined) {
token = token ?? RdDUtility.getSelectedToken(this)
const compToUse = RdDItemArme.getCompetenceArme(arme, categorieArme)
if (!RdDItemArme.isUtilisable(arme)) {
ui.notifications.warn(`Arme inutilisable: ${arme.name} non équipée ou avec une résistance de 0 ou moins`)
ui.notifications.warn(`Arme inutilisable: ${arme.name} a une résistance de 0 ou moins`)
return
}
if (!Targets.hasTargets()) {
@@ -576,37 +490,29 @@ export class RdDBaseActorReve extends RdDBaseActor {
/* -------------------------------------------- */
async encaisser() { await RdDEncaisser.encaisser(this) }
async encaisserDommages(dmg, attacker = undefined, show = undefined, attackerToken = undefined, defenderToken = undefined) {
async encaisserDommages(rollData, attacker = undefined, show = undefined, attackerToken = undefined, defenderToken = undefined) {
if (attacker && !await attacker.accorder(this, 'avant-encaissement')) {
return
return;
}
if (!Misc.isOwnerPlayer(this)) {
return RdDBaseActor.remoteActorCall({
tokenId: attackerToken?.id ?? this.token?.id,
actorId: this.id,
method: 'encaisserDommages', args: [dmg, attacker, show, attackerToken, defenderToken]
})
}
const armure = await this.computeArmure(dmg)
const armure = await this.computeArmure(rollData);
if (ReglesOptionnelles.isUsing('validation-encaissement-gr')) {
await this.encaisserDommagesValidationGR(dmg, armure, show, attackerToken, defenderToken);
await this.encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken);
}
else {
const jet = await RdDUtility.jetEncaissement(this, dmg, armure, { showDice: SHOW_DICE });
const jet = await RdDUtility.jetEncaissement(this, rollData, armure, { showDice: SHOW_DICE });
await this.$onEncaissement(jet, show, attackerToken, defenderToken)
}
}
async encaisserDommagesValidationGR(dmg, armure, show, attackerToken, defenderToken) {
async encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken) {
if (!game.user.isGM) {
RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
method: 'encaisserDommagesValidationGR', args: [dmg, armure, show, attackerToken, defenderToken]
method: 'encaisserDommagesValidationGR', args: [rollData, armure, show, attackerToken, defenderToken]
})
} else {
DialogValidationEncaissement.validerEncaissement(this, dmg, armure,
DialogValidationEncaissement.validerEncaissement(this, rollData, armure,
jet => this.$onEncaissement(jet, show, attackerToken, defenderToken));
}
}
@@ -643,37 +549,15 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
}
async encaisserRecul(force, dmgArme = 0) {
const diffRecul = this.getTaille() - force - dmgArme
const rolled = await RdDResolutionTable.roll(10, diffRecul)
if (rolled.isSuccess) {
return 'encaisse'
}
if (rolled.isETotal || (await this.rollEquilibre(diffRecul)).isEchec) {
await this.setEffect(STATUSES.StatusProne, true)
return 'chute'
}
return 'recul'
}
/* -------------------------------------------- */
async rollEquilibre(diff) {
// TODO: accrobatie optionnelle sur jet d'équilibre?
if (ReglesOptionnelles.isSet('acrobatie-pour-recul')) {
diff += Math.max(0, this.getCompetence('acrobatie')?.system.niveau ?? 0)
}
return await RdDResolutionTable.roll(this.getAgilite(), diff);
}
/* -------------------------------------------- */
async accorder(entite, when = 'avant-encaissement') {
if (when != game.settings.get(SYSTEM_RDD, "accorder-entite-cauchemar")
|| entite == undefined
|| !entite.isEntite([ENTITE_INCARNE])
|| entite.isEntiteAccordee(this)) {
return true
return true;
}
const rolled = await RdDResolutionTable.roll(this.getReveActuel(), - Number(entite.getNiveau()))
const rolled = await RdDResolutionTable.roll(this.getReveActuel(), - Number(entite.getNiveau()));
const rollData = {
alias: this.getAlias(),
rolled: rolled,
@@ -682,11 +566,11 @@ export class RdDBaseActorReve extends RdDBaseActor {
};
if (rolled.isSuccess) {
await entite.setEntiteReveAccordee(this)
await entite.setEntiteReveAccordee(this);
}
await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-accorder-cauchemar.hbs')
await this.appliquerAjoutExperience(rollData, true)
await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-accorder-cauchemar.hbs');
await this.appliquerAjoutExperience(rollData, true);
return rolled.isSuccess;
}

View File

@@ -34,17 +34,17 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
getFatigueActuelle() {
if (ReglesOptionnelles.isUsing("appliquer-fatigue")) {
return Math.max(0, Math.min(this.getFatigueMax(), Misc.toInt(this.system.sante.fatigue?.value)))
return Math.max(0, Math.min(this.getFatigueMax(), Misc.toInt(this.system.sante.fatigue?.value)))
}
return 0;
}
isCumulFatigueCauseSommeil(cumulFatigue) {
isCumulFatigueCauseSommeil(cumulFatigue){
return ReglesOptionnelles.isUsing("appliquer-fatigue")
? (this.getFatigueRestante() <= cumulFatigue)
: (this.getEnduranceActuelle() <= cumulFatigue)
? (this.getFatigueRestante() <= cumulFatigue)
: (this.getEnduranceActuelle() <= cumulFatigue)
}
getFatigueRestante() { return this.getFatigueMax() - this.getFatigueActuelle() }
getFatigueRestante() {return this.getFatigueMax() - this.getFatigueActuelle() }
getFatigueMin() { return this.system.sante.endurance.max - this.system.sante.endurance.value }
malusFatigue() {
@@ -161,7 +161,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
if (ReglesOptionnelles.isUsing("appliquer-fatigue") && sante.fatigue && fatigue > 0) {
sante.fatigue.value = Math.max(sante.fatigue.value + fatigue, this.getFatigueMin());
}
await this.update({ "system.sante": sante }, { render: true })
await this.update({ "system.sante": sante })
if (this.isDead()) {
await this.setEffect(STATUSES.StatusComma, true);
}
@@ -195,7 +195,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
const endActuelle = this.getEnduranceActuelle();
const blessure = await RdDItemBlessure.createBlessure(this, encaissement.gravite, encaissement.dmg?.loc.label ?? '', attackerToken);
if (blessure.isCritique()) {
encaissement.endurance = endActuelle
encaissement.endurance = endActuelle;
}
if (blessure.isMort()) {

View File

@@ -5,9 +5,9 @@ import { RdDSheetUtility } from "../rdd-sheet-utility.js";
import { Monnaie } from "../item-monnaie.js";
import { ITEM_TYPES } from "../constants.js";
import { RdDItem } from "../item.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js";
import { ItemAction } from "../item/item-actions.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
/* -------------------------------------------- */
/**
@@ -56,8 +56,7 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet {
this._appliquerRechercheObjets(formData.conteneurs, formData.inventaires);
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
formData.competences.filter(it => it.type == ITEM_TYPES.competencecreature)
.forEach(it => it.isdommages = it.isDommages()
)
.forEach(it => it.isdommages = RdDItemCompetenceCreature.isDommages(it))
return formData;
}

View File

@@ -1,6 +1,6 @@
import { ChatVente } from "../achat-vente/chat-vente.js";
import { ChatUtility } from "../chat-utility.js";
import { renderTemplate, SYSTEM_SOCKET_ID } from "../constants.js";
import { SYSTEM_SOCKET_ID } from "../constants.js";
import { Grammar } from "../grammar.js";
import { Monnaie } from "../item-monnaie.js";
import { ITEM_TYPES } from "../constants.js";
@@ -9,8 +9,6 @@ import { RdDAudio } from "../rdd-audio.js";
import { RdDConfirm } from "../rdd-confirm.js";
import { RdDUtility } from "../rdd-utility.js";
import { SystemCompendiums } from "../settings/system-compendiums.js";
import { RdDItem } from "../item.js";
import { STATUSES } from "../settings/status-effects.js";
export class RdDBaseActor extends Actor {
@@ -46,10 +44,8 @@ export class RdDBaseActor extends Actor {
}
static init() {
Handlebars.registerHelper('actor-isFeminin', actor => actor.isFeminin())
Hooks.on("preUpdateItem", (item, change, options, id) => Misc.documentIfResponsible(item.parent)?.onPreUpdateItem(item, change, options, id))
Hooks.on("createItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onCreateItem(item, options, id))
Hooks.on("updateItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onUpdateItem(item, options, id))
Hooks.on("deleteItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onDeleteItem(item, options, id))
Hooks.on("updateActor", (actor, change, options, actorId) => Misc.documentIfResponsible(actor)?.onUpdateActor(change, options, actorId))
}
@@ -221,7 +217,6 @@ export class RdDBaseActor extends Actor {
isHautRevant() { return false }
isVehicule() { return false }
isPersonnage() { return false }
isFeminin() { return false }
getItem(id, type = undefined) {
const item = this.items.get(id);
if (type == undefined || (item?.type == type)) {
@@ -247,28 +242,7 @@ export class RdDBaseActor extends Actor {
}
/* -------------------------------------------- */
async onPreUpdateItem(item, change, options, id) { }
async onCreateItem(item, options, id) {
switch (item.type) {
case ITEM_TYPES.blessure:
await this.changeBleedingState()
break
}
}
async onUpdateItem(item, options, id) {
switch (item.type) {
case ITEM_TYPES.blessure:
await this.changeBleedingState()
break
}
}
async changeBleedingState() {
const bleeding = this.itemTypes[ITEM_TYPES.blessure].find(it => it.isBleeding())
await this.setEffect(STATUSES.StatusBleeding, bleeding ? true : false)
}
async onCreateItem(item, options, id) { }
async onUpdateActor(update, options, actorId) { }
async onDeleteItem(item, options, id) {
if (item.isInventaire()) {
@@ -525,8 +499,7 @@ export class RdDBaseActor extends Actor {
/* -------------------------------------------- */
async computeEncTotal() {
if (!this.pack) {
this.encTotal = this.items.filter(it => RdDItem.getItemTypesInventaire().includes(it.type))
.map(it => it.getEncTotal()).reduce(Misc.sum(), 0)
this.encTotal = this.items.map(it => it.getEncTotal()).reduce(Misc.sum(), 0);
return this.encTotal;
}
return 0;
@@ -763,7 +736,7 @@ export class RdDBaseActor extends Actor {
name: this.getAlias(),
system: { description: this.system.description }
}
renderTemplate('systems/foundryvtt-reve-de-dragon/templates/post-actor.hbs', chatData)
foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/post-actor.hbs', chatData)
.then(html => ChatMessage.create(RdDUtility.chatDataSetup(html, modeOverride)));
}
@@ -785,24 +758,20 @@ export class RdDBaseActor extends Actor {
getCaracInit(competence) { return 0 }
listAttaques() {
return this.listActions({ isAttaque: true, isEquipe: false })
return this.listActions({ isAttaque: true, isEquipe:false })
}
listActions({ isAttaque = false, isEquipe = false }) { return [] }
listActions({ isAttaque = false, isEquipe=false }) { return [] }
listActionsPossessions() {
return this.itemTypes[ITEM_TYPES.possession]
.map(p => {
return {
label: p.name,
name: p.name,
action: 'possession',
possessionid: p.system.possessionid,
}
})
}
listActionsCombat() {
const possessions = this.listActionsPossessions()
return possessions.length > 0 ? possessions : this.listActions({})
}
}

View File

@@ -1,4 +1,6 @@
import { Grammar } from "../grammar.js";
import { ITEM_TYPES } from "../constants.js";
import { LIST_CARAC_AUTRES } from "../rdd-carac.js";
import { RdDBaseActorSang } from "./base-actor-sang.js";
export class RdDCreature extends RdDBaseActorSang {
@@ -43,4 +45,5 @@ export class RdDCreature extends RdDBaseActorSang {
}
return undefined
}
}

View File

@@ -3,7 +3,7 @@ import { SYSTEM_RDD } from "../../constants.js";
import { Misc } from "../../misc.js";
import { EXPORT_CSV_SCRIPTARIUM, OptionsAvancees } from "../../settings/options-avancees.js";
import { ExportScriptarium } from "./export-scriptarium.js";
import { CATEGORIES_COMPETENCES_BASE, CATEGORIES_DRACONIC, Mapping } from "./mapping.js";
import { CATEGORIES_COMPETENCES, CATEGORIES_DRACONIC, Mapping } from "./mapping.js";
export class RdDActorExportSheet extends RdDActorSheet {
static init() {
@@ -44,7 +44,7 @@ export class RdDActorExportSheet extends RdDActorSheet {
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_BASE)
formData.competences = this.getCompetences(CATEGORIES_COMPETENCES)
formData.draconic = this.getCompetences(CATEGORIES_DRACONIC)
const legeres = this.actor.nbBlessuresLegeres()
const graves = this.actor.nbBlessuresGraves()

View File

@@ -1,5 +1,5 @@
import { Grammar } from "../../grammar.js"
import { EMPOIGNADE, 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"
@@ -9,7 +9,7 @@ import { RdDBonus } from "../../rdd-bonus.js"
import { TMRType } from "../../tmr-utility.js"
export const CATEGORIES_COMPETENCES_BASE = [
export const CATEGORIES_COMPETENCES = [
"generale",
"particuliere",
"specialisee",
@@ -88,7 +88,7 @@ const MAPPING_BASE = [
{ column: "endurance_actuel", rollClass: 'jet-endurance', getter: (actor, context) => actor.system.sante.endurance.value },
{ column: "esquive", getter: (actor, context) => Mapping.getEsquive(context) },
{ column: "esquive_armure", getter: (actor, context) => Mapping.getEsquiveArmure(context) },
{ column: "competences", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_COMPETENCES_BASE) },
{ column: "competences", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_COMPETENCES) },
{ column: "draconic", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_DRACONIC) },
]
@@ -141,7 +141,7 @@ export class Mapping {
static prepareArmes(actor) {
const armes = actor.items.filter(it => it.type == ITEM_TYPES.arme)
armes.push(RdDItemArme.pugilat(actor));
armes.push(RdDItemArme.corpsACorps(actor));
armes.push(RdDItemArme.empoignade(actor));
return armes.map(arme => [
arme.system.unemain ? Mapping.prepareArme(actor, arme, '(1 main)') : undefined,
@@ -175,7 +175,7 @@ export class Mapping {
const dommages = Misc.toSignedString(dmgArme + RdDBonus.bonusDmg(actor, maniement, dmgArme))
switch (arme.system.mortalite) {
case 'non-mortel': return `(${dommages})`
case EMPOIGNADE: return '-'
case 'empoignade': return '-'
}
return dommages
}
@@ -274,10 +274,11 @@ export class Mapping {
}
static getDescription(actor) {
const naissance = actor.isFeminin() ? 'née' : 'né'
const sexe = actor.system.sexe
const sexeFeminin = sexe.length > 0 && sexe.charAt(0).toLowerCase() == 'f' ? 'Née' : 'Né'
const race = ['', 'humain'].includes(Grammar.toLowerCaseNoAccent(actor.system.race)) ? '' : (actor.system.race + ' ')
const heure = actor.system.heure
const hn = `${naissance} à l'heure ${RdDTimestamp.definition(heure).avecArticle}`
const hn = `${sexeFeminin} à l'heure ${RdDTimestamp.definition(heure).avecArticle}`
const age = (actor.system.age && actor.system.age >0) ? `${actor.system.age} ans` : undefined
const taille = actor.system.taille
const poids = actor.system.poids

View File

@@ -1,4 +1,3 @@
import { renderTemplate } from "../../constants.js";
export class TextRollManager {

View File

@@ -1,5 +1,5 @@
import { Misc } from "./misc.js";
import { renderTemplate, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
@@ -190,19 +190,15 @@ export class ChatUtility {
if (rddTimestamp) {
const timestamp = new RdDTimestamp(rddTimestamp);
const timestampData = timestamp.toCalendrier();
const dateHeure = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/common/date-heure.hbs', timestampData);
$(html).find('header.message-header .message-timestamp').after(dateHeure)
const dateHeure = await foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/common/date-heure.hbs', timestampData);
$(html).find('header.message-header .message-sender').after(dateHeure)
}
}
static async onCreateChatMessage(chatMessage, options, id) {
if (chatMessage.isAuthor) {
await ChatUtility.setTimestamp(chatMessage)
await chatMessage.setFlag(SYSTEM_RDD, 'rdd-timestamp', game.system.rdd.calendrier.getTimestamp());
await chatMessage.update({ content: await RdDTextEditor.enrichHTML(chatMessage.content, undefined, { showLink: false }) })
}
}
static async setTimestamp(chatMessage) {
await chatMessage.setFlag(SYSTEM_RDD, 'rdd-timestamp', game.system.rdd.calendrier.getTimestamp());
}
}

View File

@@ -1,6 +1,5 @@
import { RdDBaseActor } from "../actor/base-actor.js";
import { ChatUtility } from "../chat-utility.js";
import { renderTemplate } from "../constants.js";
const INFO_COEUR = 'info-coeur';

View File

@@ -9,19 +9,17 @@ export const ENTITE_INCARNE = 'incarne'
export const ENTITE_NONINCARNE = 'nonincarne'
export const ENTITE_BLURETTE = 'blurette'
export const renderTemplate = foundry.applications.handlebars.renderTemplate
export const RDD_CONFIG = {
niveauEthylisme: [
{ value: "1", label: "Aucun" },
{ value: "0", label: "Eméché (0)" },
{ value: "-1", label: "Gris (-1)" },
{ value: "-2", label: "Pinté (-2)" },
{ value: "-3", label: "Pas Frais (-3)" },
{ value: "-4", label: "Ivre (-4)" },
{ value: "-5", label: "Bu (-5)" },
{ value: "-6", label: "Complètement fait (-6)" },
{ value: "-7", label: "Ivre mort (-7)" }
niveauEthylisme : [
{value: "1", label: "Aucun"},
{value: "0", label: "Eméché (0)"},
{value: "-1", label: "Gris (-1)"},
{value: "-2", label: "Pinté (-2)"},
{value: "-3", label: "Pas Frais (-3)"},
{value: "-4", label: "Ivre (-4)"},
{value: "-5", label: "Bu (-5)"},
{value: "-6", label: "Complètement fait (-6)"},
{value: "-7", label: "Ivre mort (-7)"}
],
categorieEntite: {
"cauchemar": "Cauchemar",
@@ -32,34 +30,28 @@ export const RDD_CONFIG = {
"nonincarne": "Non Incarnée",
"blurette": "Blurette"
},
heuresRdD: [
{ value: "vaisseau", label: "Vaisseau", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd01.webp" },
{ value: "sirene", label: "Sirène", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd02.webp" },
{ value: "faucon", label: "Faucon", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd03.webp" },
{ value: "couronne", label: "Couronne", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd04.webp" },
{ value: "dragon", label: "Dragon", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd05.webp" },
{ value: "epees", label: "Epées", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd06.webp" },
{ value: "lyre", label: "Lyre", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd07.webp" },
{ value: "serpent", label: "Serpent", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd08.webp" },
{ value: "poissonacrobate", label: "Poisson Acrobate", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd09.webp" },
{ value: "araignee", label: "Araignée", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd10.webp" },
{ value: "roseau", label: "Roseau", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd11.webp" },
{ value: "chateaudormant", label: "Chateau Dormant", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd12.webp" }
heuresRdD : [
{value : "vaisseau", label: "Vaisseau", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd01.webp"},
{value : "sirene", label: "Sirène", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd02.webp"},
{value : "faucon", label: "Faucon", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd03.webp"},
{value : "couronne", label: "Couronne", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd04.webp"},
{value : "dragon", label: "Dragon", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd05.webp"},
{value : "epees", label: "Epées", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd06.webp"},
{value : "lyre", label: "Lyre", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd07.webp"},
{value : "serpent", label: "Serpent", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd08.webp"},
{value : "poissonacrobate", label: "Poisson Acrobate", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd09.webp"},
{value : "araignee", label: "Araignée", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd10.webp"},
{value : "roseau", label: "Roseau", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd11.webp"},
{value : "chateaudormant", label: "Chateau Dormant", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd12.webp"}
],
raretes: [
{ value: "Commune", label: "Commune" },
{ value: "Frequente", label: "Fréquente" },
{ value: "Rare", label: "Rare" },
{ value: "Rarissime", label: "Rarissime" }
],
particuliere: {
force: { key: 'force', descr: 'en force', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-force.svg'},
finesse: { key: 'finesse', descr: 'en finesse', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-finesse.svg'},
rapidite: { key: 'finesse', descr: 'en rapidité', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-rapidite.svg'},
}
{value: "Commune", label: "Commune"},
{value: "Frequente", label: "Fréquente"},
{value: "Rare", label: "Rare"},
{value: "Rarissime", label: "Rarissime"}
]
}
export const ACTOR_TYPES = {
personnage: 'personnage',
creature: 'creature',
@@ -114,4 +106,3 @@ export const ITEM_TYPES = {
nombreastral: 'nombreastral',
extraitpoetique: 'extraitpoetique',
}

View File

@@ -1,4 +1,3 @@
import { renderTemplate } from "./constants.js"
export class DialogChoixXpCarac extends Dialog {

View File

@@ -1,4 +1,4 @@
import { renderTemplate, SYSTEM_RDD } from "./constants.js";
import { SYSTEM_RDD } from "./constants.js";
import { Grammar } from "./grammar.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";

View File

@@ -1,5 +1,4 @@
import { ChatUtility } from "./chat-utility.js";
import { renderTemplate } from "./constants.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDItemSigneDraconique } from "./item/signedraconique.js";
import { TMRUtility } from "./tmr-utility.js";

View File

@@ -1,4 +1,3 @@
import { renderTemplate } from "./constants.js";
import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js";

View File

@@ -1,4 +1,3 @@
import { renderTemplate } from "./constants.js";
import { Misc } from "./misc.js";
export class DialogConsommer extends Dialog {

View File

@@ -1,4 +1,3 @@
import { renderTemplate } from "./constants.js"
export class DialogSelect extends Dialog {
static extractIdNameImg(it) { return { id: it.id, name: it.name, img: it.img } }

View File

@@ -1,4 +1,4 @@
import { renderTemplate } from "./constants.js";
import { Misc } from "./misc.js";
export class DialogSplitItem extends Dialog {

View File

@@ -1,4 +1,4 @@
import { HIDE_DICE, renderTemplate, SHOW_DICE } from "./constants.js";
import { HIDE_DICE, SHOW_DICE } from "./constants.js";
import { RdDUtility } from "./rdd-utility.js";
/**
@@ -7,17 +7,18 @@ import { RdDUtility } from "./rdd-utility.js";
*/
export class DialogValidationEncaissement extends Dialog {
static async validerEncaissement(actor, dmg, armure, onEncaisser) {
const encaissement = await RdDUtility.jetEncaissement(actor, dmg, armure, { showDice: HIDE_DICE });
static async validerEncaissement(actor, rollData, armure, onEncaisser) {
const encaissement = await RdDUtility.jetEncaissement(actor, rollData, armure, { showDice: HIDE_DICE });
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-validation-encaissement.hbs', {
actor: actor,
rollData: rollData,
encaissement: encaissement
});
new DialogValidationEncaissement(html, actor, dmg, armure, encaissement, onEncaisser).render(true);
new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, onEncaisser).render(true);
}
/* -------------------------------------------- */
constructor(html, actor, dmg, armure, encaissement, onEncaisser) {
constructor(html, actor, rollData, armure, encaissement, onEncaisser) {
// Common conf
let buttons = {
"valider": { label: "Valider", callback: html => this.onValider() },
@@ -41,11 +42,11 @@ export class DialogValidationEncaissement extends Dialog {
super(dialogConf, dialogOptions);
this.actor = actor
this.dmg = dmg
this.armure = armure
this.encaissement = encaissement
this.onEncaisser = onEncaisser
this.forceDiceResult = {total: encaissement.roll.result }
this.rollData = rollData;
this.armure = armure;
this.encaissement = encaissement;
this.onEncaisser = onEncaisser;
this.forceDiceResult = {total: encaissement.roll.result };
}
/* -------------------------------------------- */
@@ -54,14 +55,14 @@ export class DialogValidationEncaissement extends Dialog {
this.html = html;
this.html.find('input.encaissement-roll-result').keyup(async event => {
this.forceDiceResult.total = event.currentTarget.value;
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.dmg, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
this.html.find('label.encaissement-total').text(this.encaissement.total);
this.html.find('label.encaissement-blessure').text(this.encaissement.blessures)
});
}
async onValider() {
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.dmg, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
this.onEncaisser(this.encaissement)
}
}

View File

@@ -1,4 +1,4 @@
import { ITEM_TYPES, renderTemplate } from "../constants.js"
import { ITEM_TYPES } from "../constants.js"
import { RdDItemSort } from "../item-sort.js"
import { Misc } from "../misc.js"

View File

@@ -1,65 +1,7 @@
export const MAP_PHASE = {
possession: { label: "possession", rang: 10 },
draconic: { label: "draconic", rang: 9 },
tir: { label: "tir", rang: 8 },
lancer: { label: "lancer", rang: 7 },
arme: { label: "mêlée", rang: 5 },
pugilat: { label: "pugilat", rang: 4 },
naturelle: { label: "créature", rang: 4 },
empoignade: { label: "empoignade", rang: 3 },
autre: { label: "autre action", rang: 2 },
demi: { label: "demi-surprise", rang: 0 },
totale: { label: "surprise totale", rang: -1 },
}
export const PHASE = Object.values(MAP_PHASE)
export class RdDInitiative {
static getRollInitiative(caracValue, niveau, bonus = 0) {
const base = RdDInitiative.ajustementInitiative(caracValue, niveau, bonus)
return "1d6" + (base >= 0 ? "+" : "") + base
}
static ajustementInitiative(caracValue, niveau, bonus) {
return niveau + Math.floor(caracValue / 2) + bonus
}
static formule(phase, carac, niveau, bonusMalus) {
const ajustement = RdDInitiative.ajustementInitiative(carac, niveau, bonusMalus)
return { phase, ajustement }
}
static phaseArme(categorie, arme) {
switch (categorie) {
case "tir":
case "lancer":
return MAP_PHASE[categorie]
default:
switch (arme.system.cac) {
case "empoignade":
case "pugilat":
case "naturelle":
return MAP_PHASE[arme.system.cac]
default:
return MAP_PHASE['arme']
}
}
}
static phase(keyOrRang) {
return MAP_PHASE[keyOrRang] ?? PHASE.find(it => it.rang == keyOrRang) ?? MAP_PHASE.autre
}
static async roll(formule) {
const sign = formule.ajustement >= 0 ? "+" : ""
const roll = new Roll(`1d6 + ${sign} + ${formule.ajustement}`)
await roll.evaluate()
const value = Math.max(roll.total, 0)
return {
roll: roll,
value: value,
init: formule.phase.rang + value / 100,
label: formule.phase.label
}
static calculInitiative(niveau, caracValue, bonus = 0) {
let base = niveau + Math.floor(caracValue / 2) + bonus;
return "1d6" + (base >= 0 ? "+" : "") + base;
}
}

View File

@@ -1,7 +1,6 @@
import { Grammar } from "./grammar.js";
import { RdDItem } from "./item.js";
import { CATEGORIES_COMPETENCES, SANS_COMPETENCE } from "./item/base-items.js";
import { SANS_COMPETENCE } from "./item/base-items.js";
import { Misc } from "./misc.js";
const competenceTroncs = [["Esquive", "Dague", "Corps à corps"],
@@ -26,6 +25,16 @@ const limitesArchetypes = [
];
/* -------------------------------------------- */
export const CATEGORIES_COMPETENCES = {
"generale": { base: -4, label: "Générales" },
"particuliere": { base: -8, label: "Particulières" },
"specialisee": { base: -11, label: "Spécialisées" },
"connaissance": { base: -11, label: "Connaissances" },
"draconic": { base: -11, label: "Draconic" },
"melee": { base: -6, label: "Mêlée" },
"tir": { base: -8, label: "Tir" },
"lancer": { base: -8, label: "Lancer" }
}
function _buildCumulXP() {
let cumulXP = { "-11": 0 };
@@ -40,12 +49,7 @@ function _buildCumulXP() {
const competence_xp_cumul = _buildCumulXP();
export class RdDItemCompetence extends RdDItem {
static get ITEM_TYPE() { return ITEM_TYPES.competence }
static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp" }
export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static getLabelCategorie(category) {
return CATEGORIES_COMPETENCES[category].label;

View File

@@ -1,49 +1,87 @@
import { ITEM_TYPES } from "./constants.js";
import { RdDItem } from "./item.js";
import { Grammar } from "./grammar.js";
import { RdDInitiative } from "./initiative.mjs";
import { RdDItemArme } from "./item/arme.js";
import { RdDItem } from "./item.js";
export const CATEGORIES_COMPETENCES_CREATURES = {
"generale": { base: 0, label: "Générale" },
"naturelle": { base: 0, label: "Arme naturelle" },
"melee": { base: 0, label: "Mêlée" },
"parade": { base: 0, label: "Parade" },
"tir": { base: 0, label: "Tir" },
"lancer": { base: 0, label: "Lancer" },
"possession": { base: 0, label: "Possession" },
}
/* -------------------------------------------- */
export class RdDItemCompetenceCreature extends RdDItem {
export class RdDItemCompetenceCreature extends Item {
static get ITEM_TYPE() { return ITEM_TYPES.competencecreature }
/* -------------------------------------------- */
static setRollDataCreature(rollData) {
const code = Grammar.toLowerCaseNoAccentNoSpace(rollData.competence.name);
const selectedCarac = { code: code, label: rollData.competence.name, value: rollData.competence.system.carac_value };
rollData.carac = { [code]: selectedCarac }
rollData.competence.system.defaut_carac = code
rollData.selectedCarac = selectedCarac
rollData.arme = RdDItemCompetenceCreature.armeCreature(rollData.competence);
}
static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp" }
isAttaque() { return this.getCategorieAttaque() != undefined }
isParade() { return this.system.iscombat && (this.system.categorie_parade ?? '') != '' }
isBouclier() { return this.system.categorie_parade.includes('bouclier') }
attaqueCreature() {
const categorieAttaque = this.getCategorieAttaque()
/* -------------------------------------------- */
static armeCreature(item) {
const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(item)
if (categorieAttaque != undefined) {
const initative = RdDInitiative.getRollInitiative(this.system.carac_value, this.system.niveau);
// cloner pour ne pas modifier la compétence
return foundry.utils.mergeObject(item, {
action: item.isCompetencePossession() ? 'possession' : 'attaque',
system: {
competence: item.name,
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
niveau: item.system.niveau,
initiative: RdDInitiative.calculInitiative(item.system.niveau, item.system.carac_value),
equipe: true,
resistance: 100,
dommagesReels: item.system.dommages,
penetration: 0,
force: 0,
rapide: true,
}
}, { inplace: false, });
}
return undefined;
}
static attaqueCreature(comp) {
const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(comp)
if (categorieAttaque != undefined) {
const initative = RdDInitiative.calculInitiative(comp.system.niveau, comp.system.carac_value);
const armeComp = 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,
mortalite: comp.system.mortalite,
dommages: comp.system.dommages,
equipe: true,
resistance: 100,
penetration: 0,
force: 0,
rapide: true,
}
});
const attaque = {
label: this.name,
action: this.isCompetencePossession() ? 'possession' : 'attaque',
name: comp.name,
action: comp.isCompetencePossession() ? 'possession' : 'attaque',
initOnly: false,
arme: new RdDItemArme({
name: this.name,
type: ITEM_TYPES.arme,
img: this.img,
system: {
competence: this.name,
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
niveau: this.system.niveau,
initiative: initative,
mortalite: this.system.mortalite,
dommages: this.system.dommages,
equipe: true,
resistance: 100,
penetration: 0,
force: 0,
rapide: true,
}
}),
comp: this,
carac: { key: this.name, value: this.system.carac_value },
arme: armeComp,
comp: comp,
carac: { key: comp.name, value: comp.system.carac_value },
equipe: true,
mortalite: this.system.mortalite,
dmg: this.system.dommages,
mortalite: comp.system.mortalite,
dmg: comp.system.dommages,
initiative: initative
};
return attaque
@@ -51,24 +89,41 @@ export class RdDItemCompetenceCreature extends RdDItem {
return undefined;
}
getCategorieAttaque() {
switch (this.system.categorie) {
case "melee":
case "tir":
case "lancer":
case "naturelle":
case "possession":
return this.system.categorie
}
/* -------------------------------------------- */
static isAttaque(item) {
return RdDItemCompetenceCreature.getCategorieAttaque(item) != undefined
}
isDommages() {
switch (this.system.categorie) {
case "melee":
case "tir":
case "lancer":
case "naturelle":
return true
static getCategorieAttaque(item) {
if (item.type == ITEM_TYPES.competencecreature) {
switch (item.system.categorie) {
case "melee":
case "tir":
case "lancer":
case "naturelle":
case "possession":
return item.system.categorie
}
}
return undefined
}
static isDommages(item) {
if (item.type == ITEM_TYPES.competencecreature) {
switch (item.system.categorie) {
case "melee":
case "tir":
case "lancer":
case "naturelle":
return true
}
}
return false
}
static isParade(item) {
if (item.type == ITEM_TYPES.competencecreature) {
return item.system.categorie_parade || item.system.isparade
}
return false
}

View File

@@ -1,9 +1,7 @@
import { ACTOR_TYPES, ITEM_TYPES } from "./constants.js";
import { RdDItem } from "./item.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemSort } from "./item-sort.js";
import { RdDUtility } from "./rdd-utility.js";
import { RdDItemCompetence } from "./item-competence.js";
import { HtmlUtility } from "./html-utility.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { SYSTEM_RDD } from "./constants.js";
@@ -11,6 +9,8 @@ import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { Misc } from "./misc.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { RdDItem } from "./item.js";
import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js";
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
import { ItemAction } from "./item/item-actions.js";
@@ -106,8 +106,8 @@ export class RdDItemSheetV1 extends foundry.appv1.sheets.ItemSheet {
}
if (this.item.type == ITEM_TYPES.competencecreature) {
formData.isparade = this.item.isParade()
formData.isdommages = this.item.isDommages()
formData.isparade = RdDItemCompetenceCreature.isParade(this.item)
formData.isdommages = RdDItemCompetenceCreature.isDommages(this.item)
}
if (this.item.type == ITEM_TYPES.tache ||
this.item.type == ITEM_TYPES.livre ||

View File

@@ -1,6 +1,4 @@
import { ITEM_TYPES, renderTemplate } from "./constants.js";
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, CATEGORIES_COMPETENCES, CATEGORIES_COMPETENCES_CREATURES } from "./item/base-items.js";
import { ITEM_ACTIONS, DEFAULT_ACTIONS, COMMON_ACTIONS } from "./item/item-actions.js";
import { ITEM_TYPES } from "./constants.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
@@ -9,6 +7,10 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDUtility } from "./rdd-utility.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { RdDRaretes } from "./item/raretes.js";
import { CATEGORIES_COMPETENCES } from "./item-competence.js";
import { CATEGORIES_COMPETENCES_CREATURES } from "./item-competencecreature.js";
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE } from "./item/base-items.js";
import { ITEM_ACTIONS, DEFAULT_ACTIONS, COMMON_ACTIONS } from "./item/item-actions.js";
const typesInventaireMateriel = [
ITEM_TYPES.arme,
@@ -184,10 +186,7 @@ export class RdDItem extends Item {
isMonnaie() { return this.type == ITEM_TYPES.monnaie; }
isNourritureBoisson() { return this.type == ITEM_TYPES.nourritureboisson; }
isService() { return this.type == ITEM_TYPES.service; }
isAttaque() { return false }
isParade() { return false }
isBouclier() { return false }
getCategorieAttaque() { return undefined }
isCompetence() { return typesObjetsCompetence.includes(this.type) }
isEsquive() {
return (this.isCompetence()

View File

@@ -1,10 +1,10 @@
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";
import { MappingCreatureArme } from "./mapping-creature-arme.mjs";
import { Misc } from "../misc.js";
const nomCategorieParade = {
"sans-armes": "Sans arme",
@@ -19,56 +19,30 @@ const nomCategorieParade = {
"haches": "Haches",
"lances": "Lances",
}
export const ATTAQUE_TYPE = {
UNE_MAIN: '(1 main)',
DEUX_MAINS: '(2 mains)',
CORPS_A_CORPS: '(corps à corps)',
COMPETENCE: 'competence',
TIR: '(tir)',
LANCER: '(lancer)'
}
export const CORPS_A_CORPS = 'Corps à corps'
export const PUGILAT = 'pugilat'
export const EMPOIGNADE = 'empoignade'
/* -------------------------------------------- */
export class RdDItemArme extends RdDItem {
static get ITEM_TYPE() { return ITEM_TYPES.arme }
static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/armes_armures/epee_gnome.webp" }
static get defaultIcon() {
return defaultItemImgArme
//return "systems/foundryvtt-reve-de-dragon/icons/armes_armure/epee_sord.webp";
}
penetration() { return parseInt(this.system.penetration ?? 0) }
isParade() { return this.system.resistance > 0 && this.system.categorie_parade }
isBouclier() { return RdDItemArme.getCategorieParade(this).includes('bouclier') }
penetration() {
return parseInt(this.system.penetration ?? 0);
}
/* -------------------------------------------- */
static valeurMain(valeurs, main) {
valeurs = valeurs?.toString() ?? ""
const table = valeurs.includes("/") ? valeurs.split("/") : [valeurs, valeurs]
return parseInt(main == ATTAQUE_TYPE.DEUX_MAINS ? table[1] : table[0])
}
static getMainAttaque(competence) {
switch (competence.system.categorie) {
case 'tir': return ATTAQUE_TYPE.TIR
case 'lancer': return ATTAQUE_TYPE.LANCER
}
if (competence.name.includes('2 main')) {
return ATTAQUE_TYPE.DEUX_MAINS
}
return ATTAQUE_TYPE.UNE_MAIN
}
static getArme(arme) {
switch (arme ? arme.type : '') {
case ITEM_TYPES.arme: return arme;
case ITEM_TYPES.competencecreature:
return MappingCreatureArme.armeCreature(arme);
return RdDItemCompetenceCreature.armeCreature(arme);
}
return RdDItemArme.pugilat();
return RdDItemArme.corpsACorps();
}
static getCompetenceArme(arme, maniement) {
@@ -77,12 +51,11 @@ export class RdDItemArme extends RdDItem {
return arme.name
case ITEM_TYPES.arme:
switch (maniement) {
case ATTAQUE_TYPE.COMPETENCE: return arme.system.competence;
case ATTAQUE_TYPE.UNE_MAIN: return arme.competence1Mains()
case ATTAQUE_TYPE.DEUX_MAINS: return arme.competence2Mains()
case ATTAQUE_TYPE.TIR: case 'tir': return arme.system.tir
case ATTAQUE_TYPE.LANCER: case 'lancer': return arme.system.lancer;
case ATTAQUE_TYPE.CORPS_A_CORPS: return CORPS_A_CORPS
case 'competence': return arme.system.competence;
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
@@ -119,13 +92,16 @@ export class RdDItemArme extends RdDItem {
/* -------------------------------------------- */
static getCategorieParade(armeData) {
if (![ITEM_TYPES.arme, ITEM_TYPES.competencecreature].includes(armeData.type)) {
return ''
}
if (armeData.system.categorie_parade) {
return armeData.system.categorie_parade
}
// pour compatibilité avec des personnages existants
if (armeData.type == ITEM_TYPES.competencecreature || armeData.system.categorie == 'creature') {
return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : '')
}
if (!armeData.type.match(/arme|competencecreature/)) {
return ''
}
if (armeData.system.competence == undefined) {
return ITEM_TYPES.competencecreature;
}
@@ -220,7 +196,7 @@ export class RdDItemArme extends RdDItem {
return Number(arme.system.dommages)
}
const tableauDegats = arme.system.dommages.split("/");
return Number(tableauDegats[maniement == ATTAQUE_TYPE.UNE_MAIN ? 0 : 1])
return Number(tableauDegats[maniement == '(1 main)' ? 0 : 1])
}
return Number(arme.system.dommages);
}
@@ -229,7 +205,7 @@ export class RdDItemArme extends RdDItem {
static armeUneOuDeuxMains(arme, aUneMain) {
if (arme && !arme.system.cac) {
arme = foundry.utils.duplicate(arme);
arme.system.dommagesReels = RdDItemArme.dommagesReels(arme, aUneMain ? ATTAQUE_TYPE.UNE_MAIN : ATTAQUE_TYPE.DEUX_MAINS)
arme.system.dommagesReels = RdDItemArme.dommagesReels(arme, aUneMain ? '(1 main)' : '(2 mains)')
}
return arme;
}
@@ -250,42 +226,63 @@ export class RdDItemArme extends RdDItem {
return false
}
isAttaque() {
return this.system.resistance > 0 || (this.system.tir != '' && this.system.portee_courte > 0)
static isAttaque(arme) {
switch (arme.type) {
case ITEM_TYPES.arme: return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0)
case ITEM_TYPES.competencecreature: return arme.system.iscombat && RdDItemCompetenceCreature.isAttaque(item)
}
return false
}
static pugilat(actor) {
return RdDItemArme.$corpsACorps(actor, 'Pugilat', PUGILAT)
static isParade(arme) {
switch (arme.type) {
case ITEM_TYPES.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 empoignade(actor) {
return RdDItemArme.$corpsACorps(actor, 'Empoignade', EMPOIGNADE)
}
static $corpsACorps(actor, name, cac, system) {
const competence = actor?.getCompetenceCorpsACorps() ?? BASE_CORPS_A_CORPS
const melee = actor ? actor.system.carac['melee'].value : 0
static corpsACorps(actor) {
let competence = actor?.getCompetenceCorpsACorps() ?? BASE_CORPS_A_CORPS
let melee = actor ? actor.system.carac['melee'].value : 0
return new RdDItemArme({
_id: Misc.fakeId(cac),
name: name,
_id: competence.id,
name: 'Corps à corps',
type: ITEM_TYPES.arme,
img: competence.img,
system: {
initiative: RdDInitiative.getRollInitiative(melee, competence.system.niveau),
initiative: RdDInitiative.calculInitiative(competence.system.niveau, melee),
equipe: true,
rapide: true,
force: 0,
dommages: "0",
dommagesReels: 0,
mortalite: cac == EMPOIGNADE ? EMPOIGNADE : 'non-mortel',
competence: CORPS_A_CORPS,
mortalite: 'non-mortel',
competence: 'Corps à corps',
resistance: 1,
baseInit: cac == EMPOIGNADE ? 3 : 4,
cac: cac,
baseInit: 4,
cac: 'pugilat',
deuxmains: true,
categorie_parade: 'sans-armes'
}
})
}
static mainsNues(actor) {
const mainsNues = RdDItemArme.corpsACorps(actor)
mainsNues.name = 'Mains nues'
return mainsNues;
}
static empoignade(actor) {
const empoignade = RdDItemArme.corpsACorps(actor)
empoignade.name = 'Empoignade'
empoignade.system.cac = 'empoignade'
empoignade.system.baseInit = 3
empoignade.system.mortalite = 'empoignade'
return empoignade
}
}

View File

@@ -18,23 +18,3 @@ export const SANS_COMPETENCE = {
img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp"
}
export const CATEGORIES_COMPETENCES = {
"generale": { base: -4, label: "Générales" },
"particuliere": { base: -8, label: "Particulières" },
"specialisee": { base: -11, label: "Spécialisées" },
"connaissance": { base: -11, label: "Connaissances" },
"draconic": { base: -11, label: "Draconic" },
"melee": { base: -6, label: "Mêlée" },
"tir": { base: -8, label: "Tir" },
"lancer": { base: -8, label: "Lancer" }
}
export const CATEGORIES_COMPETENCES_CREATURES = {
"generale": { base: 0, label: "Générale" },
"naturelle": { base: 0, label: "Arme naturelle" },
"melee": { base: 0, label: "Mêlée" },
"parade": { base: 0, label: "Parade" },
"tir": { base: 0, label: "Tir" },
"lancer": { base: 0, label: "Lancer" },
"possession": { base: 0, label: "Possession" },
}

View File

@@ -209,9 +209,6 @@ export class RdDItemBlessure extends RdDItem {
isCritique() {
return this.system.gravite > 4 && this.system.gravite <= 6
}
isBleeding() {
return this.system.gravite > 2 && !this.system.premierssoins.done
}
isMort() {
return this.system.gravite > 6
}

View File

@@ -1,41 +0,0 @@
import { Grammar } from "../grammar.js";
import { RdDInitiative } from "../initiative.mjs";
export class MappingCreatureArme {
/* -------------------------------------------- */
static setRollDataCreature(rollData) {
const code = Grammar.toLowerCaseNoAccentNoSpace(rollData.competence.name);
const selectedCarac = { code: code, label: rollData.competence.name, value: rollData.competence.system.carac_value };
rollData.carac = { [code]: selectedCarac }
rollData.competence.system.defaut_carac = code
rollData.selectedCarac = selectedCarac
rollData.arme = MappingCreatureArme.armeCreature(rollData.competence);
}
/* -------------------------------------------- */
static armeCreature(item) {
const categorieAttaque = item.getCategorieAttaque()
if (categorieAttaque != undefined) {
// cloner pour ne pas modifier la compétence
return foundry.utils.mergeObject(item, {
action: item.isCompetencePossession() ? 'possession' : 'attaque',
system: {
competence: item.name,
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
niveau: item.system.niveau,
initiative: RdDInitiative.getRollInitiative(item.system.carac_value, item.system.niveau),
equipe: true,
resistance: 100,
dommagesReels: item.system.dommages,
penetration: 0,
force: 0,
rapide: true,
}
}, { inplace: false, });
}
return undefined;
}
}

View File

@@ -6,8 +6,8 @@ const tableEffets = [
{ code: "passeur", resultat: "succes", description: "Déplacer le demi-rêve à (force) cases", method: EffetsRencontre.passeur},
{ code: "reve+f", resultat: "succes", description: "Gain de (force) points de rêve" , method: EffetsRencontre.reve_plus_force},
{ code: "teleport", resultat: "succes", description: "Déplacer le demi-rêve (même type)", method: EffetsRencontre.teleportation_typecase },
{ code: "part+tete", resultat: "succes", description: "Tête de dragon sur particulière", method: EffetsRencontre.rdd_part_tete },
{ code: "part+xp", resultat: "succes", description: "Expérience sur particulière", method: EffetsRencontre.experience_particuliere },
{ code: "part+tete", resultat: "succes", description: "Tête de dragon sur réussite particulière", method: EffetsRencontre.rdd_part_tete },
{ code: "part+xp", resultat: "succes", description: "Expérience sur réussite particulière", method: EffetsRencontre.experience_particuliere },
{ code: "seuil", resultat: "succes", description: "Récupération de seuil de rêve", method: EffetsRencontre.regain_seuil },
{ code: "reve-1", resultat: "echec", description: "Perte de 1 point de rêve", method: EffetsRencontre.reve_moins_1 },
@@ -19,7 +19,7 @@ const tableEffets = [
{ code: "aleatoire", resultat: "echec", description: "Déplacement aléatoire", method: EffetsRencontre.deplacement_aleatoire },
{ code: "sort-aleatoire", resultat: "echec", description: "Déclenche un sort en réserve aléatoire", method: EffetsRencontre.sort_aleatoire },
{ code: "rompu", resultat: "echec", description: "Demi-rêve interrompu", method: EffetsRencontre.demireve_rompu },
{ code: "echec-queue", resultat: "echec", description: "Queue(s) de dragon", method: EffetsRencontre.rdd_echec_queue },
{ code: "echec-queue", resultat: "echec", description: "Queue(s) de dragon sur échec", method: EffetsRencontre.rdd_echec_queue },
{ code: "reve+1", resultat: "succes", description: "Gain de 1 point de rêve", method: EffetsRencontre.reve_plus_1 },
{ code: "vie-f", resultat: "echec", description: "Perte de (force) points de vie", method: EffetsRencontre.vie_moins_force },

View File

@@ -34,13 +34,6 @@ export class Misc {
return ((n % m) + m) % m;
}
static inRange(value, min, max) {
if (min > max) {
return Misc.inRange(value, max, min)
}
return Math.max(min, Math.min(value, max))
}
static sum() {
return (a, b) => Number(a) + Number(b);
}
@@ -65,10 +58,6 @@ export class Misc {
return 0;
}
static fakeId(base) {
return (base + foundry.utils.randomID(16)).substring(0, 16)
}
static typeName(type, subType) {
return subType ? game.i18n.localize(`TYPES.${type}.${subType}`)
: '';
@@ -119,10 +108,6 @@ export class Misc {
list.forEach(it => addToObj(obj, it))
return obj;
}
static indexed(list, index = 'index') {
let i = 0;
return list.map(it => { it[index] = i++; return it })
}
static concat(lists) {
return lists.reduce((a, b) => a.concat(b), []);

View File

@@ -1,25 +1,20 @@
import { RdDItemArme } from "./item/arme.js";
import { RdDPossession } from "./rdd-possession.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
const conditionsTactiques = [
{ key: '', label: '', dmg: 0, attaque: 0, parade: 0, esquive: true, isTactique: false },
{ key: 'normale', label: 'Attaque normale', dmg: 0, attaque: 0, parade: 0, esquive: true, isTactique: true },
{ key: 'charge', label: 'Charge', dmg: 2, attaque: 4, parade: -4, esquive: false, isTactique: true },
{ key: 'feinte', label: 'Feinte', dmg: 1, attaque: 1, parade: 0, esquive: true, isTactique: true },
{ key: 'pret', label: 'prêt', dmg: 0, attaque: 0, parade: 0, esquive: true, isTactique: false },
{ key: 'demi', label: 'Demi-surprise', dmg: 1, attaque: 0, parade: 0, esquive: true, isTactique: false },
{ key: 'totale', label: 'Surprise totale', dmg: 10, attaque: 6, parade: 0, esquive: true, isTactique: false },
{ type: '', descr: '', dmg: 0, attaque: 0, parade: 0, esquive: true },
{ type: 'charge', descr: 'Charge', dmg: 2, attaque: 4, parade: -4, esquive: false },
{ type: 'feinte', descr: 'Feinte', dmg: 1, attaque: 1, parade: 0, esquive: true },
{ type: 'pret', descr: 'prêt', dmg: 0, attaque: 0, parade: 0, esquive: true },
{ type: 'demi', descr: 'Demi-surprise', dmg: 1, attaque: 0, parade: 0, esquive: true },
{ type: 'totale', descr: 'Surprise totale', dmg: 10, attaque: 6, parade: 0, esquive: true },
];
/* -------------------------------------------- */
export class RdDBonus {
static get tactiques() {
return conditionsTactiques.filter(it => it.isTactique)
}
/* -------------------------------------------- */
static find(condition) {
return conditionsTactiques.find(e => e.key == condition) || conditionsTactiques[0];
return conditionsTactiques.find(e => e.type == condition) || conditionsTactiques.find(e => e.type == 'pret');
}
@@ -36,60 +31,36 @@ export class RdDBonus {
/* -------------------------------------------- */
static dmg(rollData, actor, isEntiteIncarnee = false) {
const diff = rollData.diffLibre;
const dmgArme = RdDBonus.dmgArme(rollData.arme, rollData.arme?.system.dommagesReels)
const forceRequise = rollData.arme ? RdDItemArme.valeurMain(rollData.arme.system.force ?? 0, RdDItemArme.getMainAttaque(rollData.competence)) : 0
let dmg = {
total: 0,
dmgArme: dmgArme,
diff: diff,
dmgDiffLibre: ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(diff ?? 0) : 0,
penetration: RdDBonus._peneration(rollData),
dmgTactique: RdDBonus.dmgBonus(rollData.tactique),
dmgParticuliere: RdDBonus._dmgParticuliere(rollData),
dmgSurprise: RdDBonus.dmgBonus(rollData.ajustements?.attaqueDefenseurSurpris.used),
mortalite: RdDBonus._calculMortalite(rollData, isEntiteIncarnee),
dmgActor: RdDBonus.bonusDmg(actor, rollData.selectedCarac?.label.toLowerCase(), dmgArme),
dmgForceInsuffisante: Math.min(0, actor.getForce() - forceRequise)
if (arme){
const dmgArme = RdDBonus.dmgArme(rollData.arme, rollData.arme.system.dommagesReels)
let dmg = {
total: 0,
dmgArme: dmgArme,
penetration: RdDBonus._peneration(rollData),
dmgTactique: RdDBonus.dmgBonus(rollData.tactique),
dmgParticuliere: RdDBonus._dmgParticuliere(rollData),
dmgSurprise: RdDBonus.dmgBonus(rollData.ajustements?.attaqueDefenseurSurpris.used),
mortalite: RdDBonus._calculMortalite(rollData, isEntiteIncarnee),
dmgActor: RdDBonus.bonusDmg(actor, rollData.selectedCarac?.label.toLowerCase(), dmgArme)
}
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere;
}
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere + dmg.dmgForceInsuffisante
return dmg;
}
static dmgRollV2(rollData, attaque) {
const actor = rollData.active.actor
const arme = attaque.arme
const dmgArme = RdDBonus.dmgArme(arme, attaque.dommagesArme)
const dmg = {
total: 0,
dmgArme: dmgArme,
penetration: arme?.penetration() ?? 0,
diff: attaque.diff,
dmgTactique: attaque.tactique?.dmg ?? 0,
dmgParticuliere: RdDBonus._dmgParticuliere(rollData),
dmgSurprise: rollData.opponent?.surprise?.dmg ?? 0,
mortalite: RdDBonus.mortalite(attaque.dmg?.mortalite, arme?.system.mortalite, rollData.opponent?.actor?.isEntite()),
dmgActor: RdDBonus.bonusDmg(actor, attaque.carac.key, dmgArme, attaque.forceRequise),
dmgForceInsuffisante: Math.min(0, actor.getForce() - attaque.forceRequise),
dmgDiffLibre: ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(attaque.diff ?? 0) : 0
}
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere + dmg.dmgForceInsuffisante + dmg.dmgDiffLibre
return dmg
}
/* -------------------------------------------- */
static description(condition) {
return RdDBonus.find(condition).label
return RdDBonus.find(condition).descr;
}
/* -------------------------------------------- */
static dmgBonus(condition) {
return RdDBonus.find(condition).dmg
return RdDBonus.find(condition).dmg;
}
/* -------------------------------------------- */
static bonusAttaque(condition) {
return RdDBonus.find(condition).attaque
return RdDBonus.find(condition).attaque;
}
/* -------------------------------------------- */
@@ -97,7 +68,7 @@ export class RdDBonus {
return RdDBonus.mortalite(rollData.dmg?.mortalite, rollData.arme?.system.mortalite, isEntiteIncarnee)
}
static mortalite(mortaliteSelect, mortaliteArme, isEntiteIncarnee) {
static mortalite( mortaliteSelect, mortaliteArme, isEntiteIncarnee) {
return isEntiteIncarnee ? "entiteincarnee"
: mortaliteSelect
?? mortaliteArme
@@ -121,10 +92,10 @@ export class RdDBonus {
/* -------------------------------------------- */
static bonusDmg(actor, categorie, dmgArme) {
const dmgActor = actor.getBonusDegat()
if (categorie == undefined) {
return 0
}
const dmgActor = actor.getBonusDegat()
switch (categorie) {
case "(tir)": case "tir": return 0
case "(lancer)": case "lancer": return Math.max(0, Math.min(dmgArme, dmgActor));

View File

@@ -52,15 +52,6 @@ export const CARACS = {
EMPATHIE: 'empathie',
REVE: 'reve',
CHANCE: 'chance',
PROTECTION: 'protection',
BEAUTE: 'beaute',
PERCEPTION: 'perception',
MELEE: 'melee',
TIR: 'tir',
LANCER: 'lancer',
DEROBEE: 'derobee',
CHANCE_ACTUELLE: 'chance-actuelle',
REVE_ACTUEL: 'reve-actuel',
}
export const LIST_CARAC_PERSONNAGE = {
[CARACS.TAILLE]: { code: CARACS.TAILLE, label: 'Taille', isCarac: true, path: 'system.carac.taille.value' },
@@ -77,21 +68,21 @@ export const LIST_CARAC_PERSONNAGE = {
[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' },
[CARACS.PROTECTION]: { code: CARACS.PROTECTION, label: 'Protection naturelle', isCarac: false, path: 'system.attributs.protection.value' },
[CARACS.BEAUTE]: { code: CARACS.BEAUTE, label: 'Beauté', isCarac: false, path: 'system.background.beaute.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' }
}
export const LIST_CARAC_AUTRES = {
[CARACS.PERCEPTION]: { code: 'perception', label: 'Perception', path: 'system.carac.perception.value' },
'perception': { code: 'perception', label: 'Perception', path: 'system.carac.perception.value' },
}
const LIST_CARAC_DERIVEE = {
[CARACS.MELEE]: { code: CARACS.MELEE, label: 'Mêlée', path: 'system.carac.melee.value' },
[CARACS.TIR]: { code: CARACS.TIR, label: 'Tir', path: 'system.carac.tir.value' },
[CARACS.LANCER]: { code: CARACS.LANCER, label: 'Lancer', path: 'system.carac.lancer.value' },
[CARACS.DEROBEE]: { code: CARACS.DEROBEE, label: 'Dérobée', path: 'system.carac.derobee.value' },
[CARACS.CHANCE_ACTUELLE]: { code: CARACS.CHANCE_ACTUELLE, label: 'Chance actuelle', path: 'system.carac.lancer.value' },
[CARACS.REVE_ACTUEL]: { code: CARACS.REVE_ACTUEL, label: 'Rêve actuel', path: 'system.reve.reve.value' },
'melee': { code: "melee", label: 'Mêlée', path: 'system.carac.melee.value' },
'tir': { code: "tir", label: 'Tir', path: 'system.carac.tir.value' },
'lancer': { code: "lancer", label: 'Lancer', path: 'system.carac.lancer.value' },
'derobee': { code: "derobee", label: 'Dérobée', path: 'system.carac.derobee.value' },
'chance-actuelle': { code: "chance-actuelle", label: 'Chance actuelle', path: 'system.carac.lancer.value' },
'reve-actuel': { code: "reve-actuel", label: 'Rêve actuel', path: 'system.reve.reve.value' },
}
export const LIST_CARAC_ROLL = Object.values(LIST_CARAC_PERSONNAGE).filter(it => it.isCarac && it.code != 'taille')
@@ -134,11 +125,11 @@ export class RdDCarac {
}
static isIntellect(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel) == CARACS.INTELLECT
return Grammar.toLowerCaseNoAccent(caracLabel) == 'intellect';
}
static isVolonte(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel) == CARACS.VOLONTE
return Grammar.toLowerCaseNoAccent(caracLabel) == 'volonte';
}
static isChance(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel)?.match(/chance(( |-)?actuelle)?/);

View File

@@ -1,5 +1,5 @@
import { ChatUtility } from "./chat-utility.js";
import { ENTITE_BLURETTE, HIDE_DICE, renderTemplate, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { ENTITE_BLURETTE, HIDE_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { RdDBonus } from "./rdd-bonus.js";
@@ -7,19 +7,14 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDRoll } from "./rdd-roll.js";
import { RdDRollTables } from "./rdd-rolltables.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
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 { EMPOIGNADE, RdDItemArme } from "./item/arme.js";
import { RdDItemArme } from "./item/arme.js";
import { RdDItemCompetence } from "./item-competence.js";
import { MAP_PHASE, RdDInitiative } from "./initiative.mjs";
import RollDialog from "./roll/roll-dialog.mjs";
import { PART_DEFENSE } from "./roll/roll-part-defense.mjs";
import { RollDialogAdapter } from "./roll/roll-dialog-adapter.mjs";
import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll/roll-constants.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js";
import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs";
import { RollBasicParts } from "./roll/roll-basic-parts.mjs";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { RdDInitiative } from "./initiative.mjs";
/* -------------------------------------------- */
const premierRoundInit = [
@@ -68,7 +63,7 @@ export class RdDCombatManager extends Combat {
if (Misc.isFirstConnectedGM()) {
await this.finDeRound({ terminer: true })
ChatUtility.removeChatMessageContaining(`<div data-combatid="${this.id}" data-combatmessage="actor-turn-summary">`)
game.messages.filter(m => ChatUtility.getMessageData(m, 'rollData') != undefined && ChatUtility.getMessageData(m, 'rollData') != undefined)
game.messages.filter(m => ChatUtility.getMessageData(m, 'attacker-roll') != undefined && ChatUtility.getMessageData(m, 'defender-roll') != undefined)
.forEach(it => it.delete())
RdDEmpoignade.deleteAllEmpoignades()
}
@@ -107,18 +102,14 @@ export class RdDCombatManager extends Combat {
return combatant.actor
}
static bonusArme(arme) {
return (arme?.system.magique) ? arme.system.ecaille_efficacite : 0
static calculAjustementInit(actor, arme) {
const efficacite = (arme?.system.magique) ? arme.system.ecaille_efficacite : 0
const etatGeneral = actor.getEtatGeneral() ?? 0
return efficacite + etatGeneral
}
static etatGeneral(actor) {
return actor.getEtatGeneral() ?? 0;
}
/** ***********************************************************************************
* @override lance l'initiative de plusieurs combattants (tous/ous les PNJs) en une fois
*/
/************************************************************************************/
async rollInitiative(ids, messageOptions = {}) {
console.log(`${game.system.title} | Combat.rollInitiative()`, ids, messageOptions)
ids = typeof ids === "string" ? [ids] : ids
@@ -126,17 +117,18 @@ export class RdDCombatManager extends Combat {
return this
}
async rollInitRdD(id, formule, messageOptions = {}) {
async rollInitRdD(id, formula, messageOptions = {}) {
const combatant = this.combatants.get(id);
const actor = RdDCombatManager.getActorCombatant(combatant)
if (actor) {
formule = formule ?? RdDCombatManager.getFirstInitRollFormula(actor)
const init = await RdDInitiative.roll(formule)
await this.updateEmbeddedDocuments("Combatant", [{
_id: combatant._id || combatant.id,
initiative: init.init, 'system.init': init
}])
const rollFormula = formula ?? RdDCombatManager.getFirstInitRollFormula(actor)
const roll = combatant.getInitiativeRoll(rollFormula);
if (!roll.total) {
await roll.evaluate();
}
const total = Math.max(roll.total, 0.00);
console.log("Compute init for", rollFormula, roll, total, combatant);
await this.updateEmbeddedDocuments("Combatant", [{ _id: combatant._id || combatant.id, initiative: total }]);
// Send a chat message
let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode");
@@ -148,10 +140,10 @@ export class RdDCombatManager extends Combat {
alias: combatant.token?.name,
sound: CONFIG.sounds.dice,
},
flavor: `${combatant.token?.name} a une initiatyive de ${init.value} : ${messageOptions.info}<br>`
flavor: `${combatant.token?.name} a fait son jet d'Initiative (${messageOptions.info})<br>`
},
messageOptions);
init.roll.toMessage(messageData, { rollMode, create: true });
roll.toMessage(messageData, { rollMode, create: true });
RdDCombatManager.processPremierRoundInit();
}
@@ -163,11 +155,16 @@ export class RdDCombatManager extends Combat {
if (actions.length > 0) {
const action = actions[0]
const init = RdDCombatManager.getInitData(actor, action)
const ajustement = RdDCombatManager.bonusArme(action.arme) + RdDCombatManager.etatGeneral(actor)
return RdDInitiative.formule(init.phase, init.carac, init.niveau, ajustement);
const ajustement = RdDCombatManager.calculAjustementInit(actor, action)
return RdDCombatManager.formuleInitiative(init.offset, init.carac, init.niveau, ajustement);
}
return RdDInitiative.formule(MAP_PHASE['autre'], 10, 0, actor.getEtatGeneral() ?? 0);
let ajustement = RdDCombatManager.calculAjustementInit(actor, undefined);
return RdDCombatManager.formuleInitiative(2, 10, 0, ajustement);
}
static formuleInitiative(rang, carac, niveau, bonusMalus) {
return `${rang} +( (${RdDInitiative.calculInitiative(niveau, carac, bonusMalus)} )/100)`;
}
/* -------------------------------------------- */
@@ -179,6 +176,7 @@ export class RdDCombatManager extends Combat {
for (let combatant of game.combat.combatants) {
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))
@@ -198,27 +196,10 @@ export class RdDCombatManager extends Combat {
}
/* -------------------------------------------- */
static applyInitiativeCommand(combatantId, command, commandValue) {
switch (command) {
case 'delta': return RdDCombatManager.incDecInit(combatantId, commandValue);
case 'autre': return RdDCombatManager.rollInitiativeAction(combatantId,
{ name: "Autre action", action: 'autre', system: { initOnly: true, competence: "Autre action" } });
}
}
static async incDecInit(combatantId, incDecValue) {
const combatant = game.combat.combatants.get(combatantId)
if (combatant?.initiative && incDecValue != 0) {
const value = combatant.system.init.value + incDecValue
const newInit = combatant.initiative + incDecValue / 100;
await game.combat.updateEmbeddedDocuments("Combatant", [{
_id: combatantId,
initiative: newInit,
'system.init.value': value,
'system.init.init': newInit,
}])
}
static incDecInit(combatantId, incDecValue) {
const combatant = game.combat.combatants.get(combatantId);
let initValue = combatant.initiative + incDecValue;
game.combat.setInitiative(combatantId, initValue);
}
/* -------------------------------------------- */
@@ -235,42 +216,56 @@ export class RdDCombatManager extends Combat {
}
}
options = [
{ name: "Incrémenter initiative", condition: true, icon: '<i class="fa-solid fa-plus"></i>', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), +1); } },
{ name: "Décrémenter initiative", condition: true, icon: '<i class="fa-solid fa-minus"></i>', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), -1); } }
{ name: "Incrémenter initiative", condition: true, icon: '<i class="fa-solid fa-plus"></i>', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), +0.01); } },
{ name: "Décrémenter initiative", condition: true, icon: '<i class="fa-solid fa-minus"></i>', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), -0.01); } }
].concat(options);
}
/* -------------------------------------------- */
static async rollInitiativeAction(combatantId, action) {
const combatant = game.combat.combatants.get(combatantId)
const actor = RdDCombatManager.getActorCombatant(combatant)
if (actor == undefined) { return [] }
if (actor == undefined) { return }
combatant.initiativeData = { arme: action } // pour reclasser l'init au round 0
const init = RdDCombatManager.getInitData(actor, action)
const ajustement = RdDCombatManager.bonusArme(actor, action.arme) + RdDCombatManager.etatGeneral(actor)
const formule = RdDInitiative.formule(init.phase, init.carac, init.niveau, ajustement);
const ajustement = RdDCombatManager.calculAjustementInit(actor, action.arme)
const rollFormula = RdDCombatManager.formuleInitiative(init.offset, init.carac, init.niveau, ajustement);
await game.combat.rollInitRdD(combatantId, formule, init);
combatant.initiativeData = { action, formule } // pour reclasser l'init au round 0
await game.combat.rollInitRdD(combatantId, rollFormula, init);
combatant.initiativeData
}
static getInitData(actor, action) {
if (actor.getSurprise() == "totale") { return { phase: MAP_PHASE['totale'], info: "Surprise Totale", carac: 0, niveau: 0 } }
if (actor.getSurprise() == "demi") { return { phase: MAP_PHASE['demi'], info: "Demi Surprise", carac: 0, niveau: 0 } }
if (action.action == 'autre') { return { phase: MAP_PHASE['autre'], info: "Autre Action", carac: 0, niveau: 0 } }
if (action.action == 'possession') { return { phase: MAP_PHASE['possession'], info: "Possession", carac: actor.getReveActuel(), niveau: 0 } }
if (action.action == 'haut-reve') { return { phase: MAP_PHASE['draconic'], info: "Draconic", carac: actor.getReveActuel(), niveau: 0 } }
if (actor.getSurprise() == "totale") { return { offset: -1, info: "Surprise Totale", carac: 0, niveau: 0 } }
if (actor.getSurprise() == "demi") { return { offset: 0, info: "Demi Surprise", carac: 0, niveau: 0 } }
if (action.action == 'autre') { return { offset: 2, info: "Autre Action", carac: 0, niveau: 0 } }
if (action.action == 'possession') { return { offset: 10, info: "Possession", carac: actor.getReveActuel(), niveau: 0 } }
if (action.action == 'haut-reve') { return { offset: 9, info: "Draconic", carac: actor.getReveActuel(), niveau: 0 } }
const comp = action.comp
return {
phase: RdDInitiative.phaseArme(comp?.system.categorie, action.arme),
info: action.label,
offset: RdDCombatManager.initOffset(comp?.system.categorie, action.arme),
info: action.name + " / " + comp.name,
carac: actor.getCaracInit(comp),
niveau: comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(action.main) ? -8 : -6)
}
}
static initOffset(categorie, arme) {
switch (categorie) {
case "tir": return 8
case "lancer": return 7
default:
switch (arme.system.cac) {
case "empoignade": return 3
case "pugilat": return 4
case "naturelle": return 4
default: return 5
}
}
}
/* -------------------------------------------- */
static displayInitiativeMenu(html, combatantId) {
const combatant = game.combat.combatants.get(combatantId)
@@ -298,8 +293,13 @@ export class RdDCombatManager extends Combat {
? possessions
: actor.listActions({ isEquipe: true })
return Misc.indexed(actions)
for (let index = 0; index < actions.length; index++) {
actions[index].index = index
}
return actions
}
}
/* -------------------------------------------- */
@@ -368,7 +368,7 @@ export class RdDCombat {
if (Misc.isOwnerPlayer(defender)) {
let attackerRoll = msg.attackerRoll;
let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : undefined;
defender.encaisserDommages(attackerRoll.dmg, attacker, msg.attackerToken);
defender.encaisserDommages(attackerRoll, attacker, msg.attackerToken);
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id);
rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
}
@@ -379,13 +379,8 @@ export class RdDCombat {
let defenderToken = canvas.tokens.get(msg.defenderToken.id)
if (defenderToken && Misc.isFirstConnectedGM()) {
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id)
rddCombat?.removeChatMessageActionsPasseArme(msg.paramChatDefense.attackerRoll.passeArme)
if (msg.defenderRoll.ids) {/* TODO: delete roll V1 */
RollDialog.loadRollData(msg.paramChatDefense)
rddCombat?._chatMessageDefenseV2(msg.paramChatDefense)
} else {
rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll)
}
rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme)
rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll)
}
}
@@ -403,19 +398,15 @@ export class RdDCombat {
/* -------------------------------------------- */
static registerChatCallbacks(html) {
for (let button of [
'.button-defense',
'.button-parade',
'.button-esquive',
'.button-encaisser',
'.parer-button',
'.esquiver-button',
'.particuliere-attaque',
'.encaisser-button',
'.appel-chance-defense',
'.appel-destinee-defense',
'.appel-chance-attaque',
'.appel-destinee-attaque',
'.echec-total-attaque',
// '.appel-chance',
// '.chat-encaissement',
// '.resister-recul',
]) {
$(html).on("click", button, event => {
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(
@@ -465,8 +456,8 @@ export class RdDCombat {
/* -------------------------------------------- */
async onEvent(button, event) {
const chatMessage = ChatUtility.getChatMessage(event);
const defenderRoll = ChatUtility.getMessageData(chatMessage, 'rollData');
const attackerRoll = defenderRoll?.attackerRoll ?? ChatUtility.getMessageData(chatMessage, 'rollData');
const defenderRoll = ChatUtility.getMessageData(chatMessage, 'defender-roll');
const attackerRoll = defenderRoll?.attackerRoll ?? ChatUtility.getMessageData(chatMessage, 'attacker-roll');
console.log('RdDCombat', attackerRoll, defenderRoll);
const armeParadeId = event.currentTarget.attributes['data-armeid']?.value;
@@ -475,11 +466,9 @@ export class RdDCombat {
switch (button) {
case '.particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value);
case '.button-defense': return this.defenseV2(attackerRoll);
case '.button-parade': return this.parade(attackerRoll, armeParadeId);
case '.button-esquive': return this.esquive(attackerRoll, compId, competence);
case '.button-encaisser': return this.encaisser(attackerRoll, defenderRoll);
case '.parer-button': return this.parade(attackerRoll, armeParadeId);
case '.esquiver-button': return this.esquive(attackerRoll, compId, competence);
case '.encaisser-button': return this.encaisser(attackerRoll, defenderRoll);
case '.echec-total-attaque': return this._onEchecTotal(attackerRoll);
case '.appel-chance-attaque': return this.attacker.rollAppelChance(
@@ -489,9 +478,11 @@ export class RdDCombat {
() => this.defenseChanceuse(attackerRoll, defenderRoll),
() => this.afficherOptionsDefense(attackerRoll, defenderRoll, { defenseChance: true }));
case '.appel-destinee-attaque': return this.attacker.appelDestinee(
() => this.attaqueSignificative(attackerRoll));
() => this.attaqueSignificative(attackerRoll),
() => { });
case '.appel-destinee-defense': return this.defender.appelDestinee(
() => this.defenseDestinee(defenderRoll));
() => this.defenseDestinee(defenderRoll),
() => { });
}
}
@@ -561,42 +552,27 @@ export class RdDCombat {
/* -------------------------------------------- */
static isEchecTotal(rollData) {
if (rollData.ids /* roll V2*/) {
// TODO: en cas de demi-surprise à l'attaque, tout échec est un echec total.
// TODO: en cas de demi-surprise en défense, pas de changement à la règle de base
return rollData.rolled.isETotal
if (!rollData.attackerRoll && rollData.ajustements.surprise.used) {
return rollData.rolled.isEchec && rollData.rolled.code != 'notSign';
}
if (rollData.mode == ROLL_TYPE_ATTAQUE && rollData.surprise == 'demi') {
// échec normal à l'attaque en demi surprise
return rollData.rolled.isEchec && rollData.rolled.code != 'notSign'
}
return rollData.rolled.isETotal
return rollData.rolled.isETotal;
}
/* -------------------------------------------- */
static isParticuliere(rollData) {
if (rollData.ids /* roll V2*/) {
return rollData.rolled.isPart
if (!rollData.attackerRoll && rollData.ajustements.surprise.used) {
return false;
}
if (rollData.attackerRoll || !rollData.ajustements.surprise.used) {
return rollData.rolled.isPart
}
return false
return rollData.rolled.isPart;
}
/* -------------------------------------------- */
static isReussite(rollData) {
if (rollData.ids /* roll V2*/) {
return rollData.rolled.isSuccess
}
if (!rollData.ajustements.surprise.used) {
return rollData.rolled.isSuccess
}
switch (rollData.ajustements.surprise.used) {
case 'totale': return false
case 'demi': return rollData.rolled.isSign
case 'totale': return false;
case 'demi': return rollData.rolled.isSign;
}
return rollData.rolled.isSuccess
return rollData.rolled.isSuccess;
}
/* -------------------------------------------- */
@@ -666,101 +642,12 @@ export class RdDCombat {
return { msg: "à déterminer (0 immobile, -3 actif, -4 en mouvement, -5 en zig-zag)", diff: -3 };
}
async attaqueV2() {
if (!await this.attacker.accorder(this.defender, 'avant-attaque')) {
return
}
await this.doRollAttaque({
ids: {
actorId: this.attackerId,
actorTokenId: this.attackerTokenId,
opponentId: this.defender.id,
opponentTokenId: this.defenderTokenId,
},
type: { allowed: ['attaque'], current: 'attaque' },
passeArme: foundry.utils.randomID(16),
})
}
async doRollAttaque(rollData, callbacks = []) {
// TODO V2 await this.proposerAjustementTirLancer(rollData)
await RollDialog.create(rollData, {
onRollDone: (dialog) => {
if (!OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST))
dialog.close()
},
customChatMessage: true,
callbacks: [
async (roll) => await this.onAttaqueV2(roll),
...callbacks
]
})
}
async onAttaqueV2(attackerRoll) {
if (!this.defender || !attackerRoll.rolled.isSuccess || attackerRoll.particulieres?.length > 1) {
return
}
if (!await this.attacker.accorder(this.defender, 'avant-defense')) {
return;
}
RollDialog.loadRollData(attackerRoll)
const surpriseDefender = this.defender.getSurprise(true);
const paramChatDefense = {
attackerRoll: attackerRoll,
isPossession: this.isPossession(attackerRoll),
defender: this.defender,
attacker: this.attacker,
attackerId: this.attackerId,
attackerToken: this.attackerToken,
defenderToken: this.defenderToken,
surprise: surpriseDefender,
}
if (Misc.isFirstConnectedGM()) {
await this._chatMessageDefenseV2(paramChatDefense);
}
else {
this._socketSendMessageDefense(paramChatDefense, {});
}
}
async _chatMessageDefenseV2(paramDemandeDefense) {
const attackerRoll = paramDemandeDefense.attackerRoll;
RollBasicParts.loadSurprises(attackerRoll)
attackerRoll.passeArme = attackerRoll.passeArme ?? foundry.utils.randomID(16)
attackerRoll.dmg = RdDBonus.dmgRollV2(attackerRoll, attackerRoll.current.attaque)
// attackerRoll.current.attaque.dmg = attackerRoll.dmg
// attaque.dmg = attackerRoll.current.attaque.dmg
const attaque = RollDialog.saveParts(attackerRoll)
const defense = {
attackerRoll: attaque,
ids: RollBasicParts.reverseIds(attaque),
passeArme: attaque.passeArme ?? foundry.utils.randomID(16)
}
const choixDefense = await ChatMessage.create({
// message privé: du défenseur à lui même (et aux GMs)
speaker: ChatMessage.getSpeaker(this.defender, canvas.tokens.get(this.defenderTokenId)),
alias: this.attacker?.getAlias(),
whisper: ChatUtility.getOwners(this.defender),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.hbs', attackerRoll)
});
// flag pour garder les jets d'attaque/defense
ChatUtility.setMessageData(choixDefense, 'rollData', defense)
}
/* -------------------------------------------- */
async attaque(competence, arme) {
if (!await this.attacker.accorder(this.defender, 'avant-attaque')) {
return
}
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
return this.attacker.rollCompetence(competence.name, { arme: arme })
}
if (arme.system.cac == EMPOIGNADE) {
if (arme.system.cac == 'empoignade') {
RdDEmpoignade.onAttaqueEmpoignade(this.attacker, this.defender)
return
}
@@ -792,7 +679,6 @@ export class RdDCombat {
/* -------------------------------------------- */
_prepareAttaque(competence, arme) {
let rollData = {
mode: ROLL_TYPE_ATTAQUE,
alias: this.attacker?.getAlias(),
passeArme: foundry.utils.randomID(16),
mortalite: arme?.system.mortalite,
@@ -805,7 +691,7 @@ export class RdDCombat {
};
if (this.attacker.isCreatureEntite()) {
MappingCreatureArme.setRollDataCreature(rollData);
RdDItemCompetenceCreature.setRollDataCreature(rollData);
}
else if (arme) {
// Usual competence
@@ -813,9 +699,9 @@ export class RdDCombat {
}
else {
// sans armes: à mains nues
rollData.arme = RdDItemArme.pugilat(this.attacker)
rollData.arme = RdDItemArme.corpsACorps(this.attacker)
rollData.arme.system.niveau = competence.system.niveau
rollData.arme.system.initiative = RdDInitiative.getRollInitiative(this.attacker.system.carac['melee'].value, competence.system.niveau);
rollData.arme.system.initiative = RdDInitiative.calculInitiative(competence.system.niveau, this.attacker.system.carac['melee'].value);
}
return rollData;
}
@@ -827,6 +713,9 @@ export class RdDCombat {
if (RdDCombat.isReussite(attackerRoll)) {
return await this._onAttaqueNormale(attackerRoll)
}
// if (RdDCombat.isParticuliere(attackerRoll) && attackerRoll.particuliere == undefined) {
// return
// }
if (RdDCombat.isEchecTotal(attackerRoll)) {
return await this._onAttaqueEchecTotal(attackerRoll)
}
@@ -866,7 +755,7 @@ export class RdDCombat {
passeArme: rollData.passeArme
})
});
ChatUtility.setMessageData(choixParticuliere, 'rollData', rollData);
ChatUtility.setMessageData(choixParticuliere, 'attacker-roll', rollData);
}
/* -------------------------------------------- */
@@ -897,6 +786,8 @@ export class RdDCombat {
/* -------------------------------------------- */
async _sendMessageDefense(attackerRoll, defenderRoll, essaisPrecedents = undefined) {
console.log("RdDCombat._sendMessageDefense", attackerRoll, defenderRoll, essaisPrecedents, " / ", this.attacker, this.target, this.attackerId, attackerRoll.competence.system.categorie);
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
if (essaisPrecedents) {
foundry.utils.mergeObject(attackerRoll.essais, essaisPrecedents, { overwrite: true });
@@ -942,10 +833,10 @@ export class RdDCombat {
speaker: ChatMessage.getSpeaker(this.defender, canvas.tokens.get(this.defenderTokenId)),
alias: this.attacker?.getAlias(),
whisper: ChatUtility.getOwners(this.defender),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense-v1.hbs', paramDemandeDefense),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.hbs', paramDemandeDefense),
});
// flag pour garder les jets d'attaque/defense
ChatUtility.setMessageData(choixDefense, 'rollData', defenderRoll);
ChatUtility.setMessageData(choixDefense, 'defender-roll', defenderRoll);
}
/* -------------------------------------------- */
@@ -959,14 +850,14 @@ export class RdDCombat {
defenderToken: this.defenderToken,
defenderRoll: defenderRoll,
paramChatDefense: paramChatDefense,
rollMode: true,
rollMode: true
}
});
}
/* -------------------------------------------- */
_filterArmesParade(defender, competence, armeAttaque) {
let defenses = defender.items.filter(it => it.isParade())
let defenses = defender.items.filter(it => RdDItemArme.isParade(it))
defenses = foundry.utils.duplicate(defenses)
defenses.forEach(armeDefense => {
// Ajout du # d'utilisation ce round
@@ -988,7 +879,6 @@ export class RdDCombat {
const choixEchecTotal = await ChatMessage.create({
whisper: ChatUtility.getOwners(this.attacker),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.hbs', {
rolled: attackerRoll.rolled,
attackerId: this.attackerId,
attacker: this.attacker,
attackerToken: this.attackerToken,
@@ -996,7 +886,7 @@ export class RdDCombat {
essais: attackerRoll.essais
})
});
ChatUtility.setMessageData(choixEchecTotal, 'rollData', attackerRoll);
ChatUtility.setMessageData(choixEchecTotal, 'attacker-roll', attackerRoll);
}
/* -------------------------------------------- */
@@ -1056,44 +946,9 @@ export class RdDCombat {
dialog.render(true);
}
async defenseV2(attackerRoll) {
// this._prepareParade(attackerRoll, arme, competence);
RollDialog.loadRollData(attackerRoll)
await this.doRollDefense({
ids: {
actorId: this.defender.id,
actorTokenId: this.defenderTokenId,
opponentTokenId: this.attackerTokenId,
opponentId: this.attackerId,
},
type: { allowed: [ROLL_TYPE_DEFENSE], current: ROLL_TYPE_DEFENSE },
attackerRoll: RollDialogAdapter.mapActionAttaque(attackerRoll),
passeArme: attackerRoll.passeArme,
})
}
async doRollDefense(rollData, callbacks = []) {
await RollDialog.create(rollData, {
onRollDone: RollDialog.onRollDoneClose,
customChatMessage: true,
callbacks: [
async (roll) => {
this.removeChatMessageActionsPasseArme(roll.passeArme);
// defense: esquive / arme de parade / competence de défense
if (!RdDCombat.isParticuliere(roll)) {
await roll.active.actor.incDecItemUse(roll.current[PART_DEFENSE].defense?.id);
}
await this._onDefense(roll);
},
...callbacks
]
})
}
/* -------------------------------------------- */
_prepareParade(attackerRoll, armeParade, competenceParade) {
let defenderRoll = {
mode: ROLL_TYPE_DEFENSE,
alias: this.defender?.getAlias(),
passeArme: attackerRoll.passeArme,
diffLibre: attackerRoll.diffLibre,
@@ -1110,47 +965,12 @@ export class RdDCombat {
};
if (this.defender.isCreatureEntite()) {
MappingCreatureArme.setRollDataCreature(defenderRoll);
RdDItemCompetenceCreature.setRollDataCreature(defenderRoll);
}
return defenderRoll;
}
async _onDefense(rollData) {
const isEsquive = rollData.current[PART_DEFENSE].isEsquive
const isParade = !isEsquive
if (RdDCombat.isReussite(rollData)) {
if (isParade) {
await this.computeDeteriorationArme(rollData)
if (RdDCombat.isParticuliere(rollData)) {
await this.infoAttaquantDesarme(rollData)
}
}
}
this.removeChatMessageActionsPasseArme(rollData.passeArme)
}
async infoAttaquantDesarme(rollData) {
if (/*TODO: parade?*/!rollData.attackerRoll?.particuliere) {
// TODO: attaquant doit jouer résistance et peut être désarmé p132
ChatUtility.createChatWithRollMode(
{ content: `(à gérer) L'attaquant doit jouer résistance et peut être désarmé (p132)` },
this.defender)
}
}
async _onDefenseNormale(rollData) {
console.log("RdDCombat._onDefenseNormale >>>", rollData);
await this.computeRecul(rollData);
await this.computeDeteriorationArme(rollData);
await RdDRollResult.displayRollData(rollData, this.defender, 'chat-resultat-parade.hbs');
this.removeChatMessageActionsPasseArme(rollData.passeArme);
}
async _onParade(defenderRoll) {
if (RdDCombat.isReussite(defenderRoll)) {
@@ -1222,7 +1042,6 @@ export class RdDCombat {
/* -------------------------------------------- */
_prepareEsquive(attackerRoll, competence) {
let rollData = {
mode: ROLL_TYPE_DEFENSE,
alias: this.defender.getAlias(),
passeArme: attackerRoll.passeArme,
diffLibre: attackerRoll.diffLibre,
@@ -1237,7 +1056,7 @@ export class RdDCombat {
};
if (this.defender.isCreatureEntite()) {
MappingCreatureArme.setRollDataCreature(rollData);
RdDItemCompetenceCreature.setRollDataCreature(rollData);
}
return rollData;
}
@@ -1286,7 +1105,7 @@ export class RdDCombat {
// Est-ce une parade normale?
if (defenderRoll.arme && attackerRoll && !defenderRoll.rolled.isPart) {
// Est-ce que l'attaque est une particulière en force ou une charge
if (defenderRoll.needResist || this._isForceOuCharge(attackerRoll, defenderRoll.v2)) {
if (defenderRoll.needResist || this._isForceOuCharge(attackerRoll)) {
defenderRoll.show = defenderRoll.show || {}
@@ -1334,7 +1153,7 @@ export class RdDCombat {
finalLevel: Misc.toInt(defenderRoll.competence.system.niveau) - dmg,
showDice: HIDE_DICE
});
defenderRoll.show.desarme = desarme.rolled.isEchec
defenderRoll.show.desarme = desarme.rolled.isEchec;
}
}
}
@@ -1342,19 +1161,41 @@ export class RdDCombat {
/* -------------------------------------------- */
async computeRecul(defenderRoll) { // Calcul du recul (p. 132)
if (!ReglesOptionnelles.isUsing('recul')) {
return
}
const attackerRoll = defenderRoll.attackerRoll;
if (this._isForceOuCharge(attackerRoll, defenderRoll.v2)) {
defenderRoll.show.recul = this.defender.encaisserRecul(this.attacker.getForce(), attackerRoll.dmg.dmgArme)
if (ReglesOptionnelles.isUsing('recul') && this._isForceOuCharge(attackerRoll)) {
const impact = this._computeImpactRecul(attackerRoll);
const rollRecul = await RdDResolutionTable.rollData({ caracValue: 10, finalLevel: impact });
if (rollRecul.rolled.isSuccess) {
defenderRoll.show.recul = 'encaisse';
} else if (rollRecul.rolled.isETotal || this._isReculCauseChute(impact)) {
defenderRoll.show.recul = 'chute';
await this.defender.setEffect(STATUSES.StatusProne, true);
}
else {
defenderRoll.show.recul = 'recul';
}
}
}
_isForceOuCharge(attaque, isRollV2 = false /* TODO: delete roll V1 */) {
return attaque.particuliere == 'force' || 'charge' == (isRollV2 ? attaque.tactique?.key : attaque.tactique)
/* -------------------------------------------- */
async _isReculCauseChute(impact) {
const agilite = this.defender.getAgilite();
const chute = await RdDResolutionTable.rollData({ caracValue: agilite, finalLevel: impact });
return chute.rolled.isEchec;
}
/* -------------------------------------------- */
_isForceOuCharge(attaque) {
return attaque.particuliere == 'force' || attaque.tactique == 'charge';
}
/* -------------------------------------------- */
_computeImpactRecul(attaque) {
const taille = this.defender.getTaille();
const force = this.attacker.getForce();
const dommages = attaque.arme.system.dommagesReels ?? attaque.arme.system.dommages;
return taille - (force + dommages);
}
/* -------------------------------------------- */
async encaisser(attackerRoll, defenderRoll) {
@@ -1364,16 +1205,12 @@ export class RdDCombat {
this._onEchecTotal(defenderRoll);
}
await this.doRollEncaissement(attackerRoll, defenderRoll);
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
}
async doRollEncaissement(attackerRoll, defenderRoll) {
if (Misc.isOwnerPlayer(this.defender)) {
attackerRoll.attackerId = this.attackerId;
attackerRoll.defenderTokenId = this.defenderToken.id;
await this.computeRecul(defenderRoll);
await this.defender.encaisserDommages(attackerRoll.dmg, this.attacker, defenderRoll?.show, this.attackerToken, this.defenderToken);
await this.defender.encaisserDommages(attackerRoll, this.attacker, defenderRoll?.show, this.attackerToken, this.defenderToken);
}
else { // envoi à un GM: les joueurs n'ont pas le droit de modifier les personnages qu'ils ne possèdent pas
game.socket.emit(SYSTEM_SOCKET_ID, {
@@ -1384,8 +1221,9 @@ export class RdDCombat {
attackerToken: this.attackerToken,
defenderToken: this.defenderToken
}
})
});
}
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
}
/* -------------------------------------------- */
@@ -1417,5 +1255,4 @@ export class RdDCombat {
alias: alias
})
}
}
}

View File

@@ -19,7 +19,6 @@ import { TMRUtility } from "./tmr-utility.js";
import { DialogFatigueVoyage } from "./voyage/dialog-fatigue-voyage.js";
import { ChatUtility } from "./chat-utility.js";
import { RdDRollResult } from "./rdd-roll-result.js";
import { renderTemplate } from "./constants.js";
const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/;

View File

@@ -1,9 +1,10 @@
import { STATUSES } from "./settings/status-effects.js";
import { ITEM_TYPES, renderTemplate } from "./constants.js";
import { ChatUtility } from "./chat-utility.js";
import { RdDRollResult } from "./rdd-roll-result.js";
/* -------------------------------------------- */
import { RdDRoll } from "./rdd-roll.js";
import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { ChatUtility } from "./chat-utility.js";
import { STATUSES } from "./settings/status-effects.js";
import { ITEM_TYPES } from "./constants.js";
import { RdDRollResult } from "./rdd-roll-result.js";
/* -------------------------------------------- */
export class RdDEmpoignade {
@@ -185,7 +186,7 @@ export class RdDEmpoignade {
malusTaille: RdDEmpoignade.getMalusTaille(empoignade, attacker, defender)
}
if (attacker.isCreatureEntite()) {
MappingCreatureArme.setRollDataCreature(rollData)
RdDItemCompetenceCreature.setRollDataCreature(rollData)
}
if (empoignade.system.pointsemp >= 2) {
if (!empoignade.system.ausol) {

View File

@@ -1,4 +1,5 @@
import { ATTAQUE_TYPE, EMPOIGNADE, PUGILAT, RdDItemArme } from "./item/arme.js";
import { RdDItemArme } from "./item/arme.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { ITEM_TYPES } from "./constants.js";
export class RdDHotbar {
@@ -19,17 +20,14 @@ export class RdDHotbar {
await game.user.assignHotbarMacro(macro, slot);
}
static $macroNameSuffix(maniement) {
switch (maniement) {
case ATTAQUE_TYPE.UNE_MAIN:
case ATTAQUE_TYPE.DEUX_MAINS:
case ATTAQUE_TYPE.LANCER:
case ATTAQUE_TYPE.TIR:
return ' ' + maniement
static $macroNameSuffix(armeCompetence) {
switch (armeCompetence) {
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)';
case 'pugilat': return ' (pugilat)';
case 'empoignade': return ' (empoignade)';
}
return ''
}
@@ -41,30 +39,30 @@ export class RdDHotbar {
// Les armes peuvent avoir plusieurs usages
if (item.system.competence != '') {
if (item.system.unemain) {
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.UNE_MAIN)
await this.createItemMacro(item, slot++, '(1 main)')
}
if (item.system.deuxmains) {
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.DEUX_MAINS)
await this.createItemMacro(item, slot++, '(2 mains)')
}
}
if (item.system.lancer != '') {
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.LANCER)
await this.createItemMacro(item, slot++, 'lancer')
}
if (item.system.tir != '') {
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.TIR)
await this.createItemMacro(item, slot++, 'lancer')
}
}
return
case ITEM_TYPES.competencecreature:
const categorie = item.getCategorieAttaque() ?? 'competence';
const categorie = RdDItemCompetenceCreature.getCategorieAttaque(item) ?? 'competence';
await this.createItemMacro(item, slot, categorie)
return
default:
case ITEM_TYPES.competence:
await this.createItemMacro(item, slot++, 'competence')
if (item.isCorpsACorps()) {
await this.createItemMacro(item, slot++, PUGILAT)
await this.createItemMacro(item, slot++, EMPOIGNADE)
await this.createItemMacro(item, slot++, 'pugilat')
await this.createItemMacro(item, slot++, 'empoignade')
}
else if (item.isCompetenceArme()) {
ui.notifications.info(`${item.name} est une compétence d'arme, la macro n'est pas liée à un arme.<br>
@@ -121,15 +119,15 @@ export class RdDHotbar {
case ITEM_TYPES.competence:
if (item.isCorpsACorps()) {
switch (categorieArme) {
case PUGILAT:
return actor.rollArme(RdDItemArme.pugilat(actor));
case EMPOIGNADE:
case 'pugilat':
return actor.rollArme(RdDItemArme.corpsACorps(actor));
case 'empoignade':
return actor.rollArme(RdDItemArme.empoignade(actor));
}
}
return actor.rollCompetence(item);
case ITEM_TYPES.competencecreature:
return item.system.iscombat
return item.system.iscombat && !item.system.isparade
? actor.rollArme(item, categorieArme)
: actor.rollCompetence(item);

View File

@@ -45,8 +45,6 @@ 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 { RdDItemCompetence } from "./item-competence.js"
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"
import { RdDItemGemme } from "./item/gemme.js"
import { RdDItemMaladie } from "./item/maladie.js"
import { RdDItemOmbre } from "./item/ombre.js"
@@ -88,7 +86,6 @@ import { RdDCombatManager, RdDCombat } from "./rdd-combat.js"
import { Migrations } from './migrations.js'
import RollDialog from "./roll/roll-dialog.mjs"
import ChatRollResult from "./roll/chat-roll-result.mjs"
/**
* RdD system
@@ -115,8 +112,6 @@ export class SystemReveDeDragon {
arme: RdDItemArme,
armure: RdDItemArmure,
blessure: RdDItemBlessure,
competence: RdDItemCompetence,
competencecreature: RdDItemCompetenceCreature,
gemme: RdDItemGemme,
maladie: RdDItemMaladie,
ombre: RdDItemOmbre,
@@ -297,7 +292,6 @@ export class SystemReveDeDragon {
TMRRencontres.init()
ExportScriptarium.init()
RollDialog.init()
ChatRollResult.init()
}
initSettings() {
@@ -352,7 +346,18 @@ export class SystemReveDeDragon {
})
}
static async setupAccueil() {
let exists = game.scenes.find(j => j.name == "Accueil RdD");
if (!exists) {
const scenes = await SystemCompendiums.loadCompendium("foundryvtt-reve-de-dragon.scenes-rdd")
let newDocuments = scenes.filter(i => i.name == "Accueil RdD");
await game.scenes.documentClass.create(newDocuments);
game.scenes.find(i => i.name == "Accueil RdD").activate();
}
}
async onReady() {
/* -------------------------------------------- */
/* Foundry VTT Initialization */
/* -------------------------------------------- */
@@ -371,8 +376,7 @@ export class SystemReveDeDragon {
StatusEffects.onReady()
RdDDice.onReady()
RollDialog.onReady()
ChatRollResult.onReady()
RdDStatBlockParser.parseStatBlock()
/* -------------------------------------------- */
/* Affiche/Init le calendrier */
game.system.rdd.calendrier.display()
@@ -385,17 +389,7 @@ export class SystemReveDeDragon {
})
}
this.setupAccueil()
}
async setupAccueil() {
let exists = game.scenes.find(j => j.name == "Accueil RdD");
if (!exists) {
const scenes = await SystemCompendiums.loadCompendium("foundryvtt-reve-de-dragon.scenes-rdd")
let newDocuments = scenes.filter(i => i.name == "Accueil RdD");
await game.scenes.documentClass.create(newDocuments);
game.scenes.find(i => i.name == "Accueil RdD").activate();
}
SystemReveDeDragon.setupAccueil()
}
/* -------------------------------------------- */

View File

@@ -1,5 +1,4 @@
import { ChatUtility } from "./chat-utility.js"
import { renderTemplate } from "./constants.js"
const vents = [
{ min: 0, max: 0, valeur: 'Calme' },

View File

@@ -1,6 +1,5 @@
import { RdDBaseActor } from "./actor/base-actor.js";
import { ChatUtility } from "./chat-utility.js";
import { renderTemplate } from "./constants.js";
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";

View File

@@ -1,7 +1,9 @@
import { RdDRoll } from "./rdd-roll.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { Targets } from "./targets.js";
import { ITEM_TYPES } from "./constants.js";
import { RdDRollResult } from "./rdd-roll-result.js";
import { Grammar } from "./grammar.js";
/* -------------------------------------------- */
/* On part du principe qu'une entité démarre tjs

View File

@@ -1,4 +1,3 @@
import { renderTemplate } from "./constants.js";
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
@@ -67,9 +66,9 @@ export class RdDResolutionTable {
}
/* -------------------------------------------- */
static _computeCell(level, percentage) {
static _computeCell(niveau, percentage) {
return {
level: level,
niveau: niveau,
score: percentage,
norm: Math.min(99, percentage),
sign: this._reussiteSignificative(percentage),
@@ -158,7 +157,7 @@ export class RdDResolutionTable {
/* -------------------------------------------- */
static significativeRequise(chances) {
chances.roll = Math.min(chances.part + 1, chances.sign)
chances.roll = Math.floor(chances.score / 2);
foundry.utils.mergeObject(chances, reussites.find(x => x.code == 'sign'), { overwrite: true });
}
@@ -186,14 +185,46 @@ export class RdDResolutionTable {
}
/* -------------------------------------------- */
static computeReussite(chances, roll, diviseur) {
const reussite = reussites.find(x => x.condition(chances, roll))
if (diviseur > 1 && reussite.isSuccess) {
if (chances.norm < roll * diviseur) {
return reussiteInsuffisante
}
static isEchec(rollData) {
switch (rollData.surprise) {
case 'demi': return !rollData.rolled.isSign;
case 'totale': return true;
}
return reussite
return rollData.rolled.isEchec;
}
/* -------------------------------------------- */
static isEchecTotal(rollData) {
if (rollData.arme && rollData.surprise == 'demi') {
return rollData.rolled.isEchec;
}
return rollData.rolled.isETotal;
}
/* -------------------------------------------- */
static isParticuliere(rollData) {
if (rollData.arme && rollData.surprise) {
return false;
}
return rollData.rolled.isPart;
}
/* -------------------------------------------- */
static isReussite(rollData) {
switch (rollData.surprise) {
case 'demi': return rollData.rolled.isSign;
case 'totale': return false;
}
return rollData.rolled.isSuccess;
}
/* -------------------------------------------- */
static computeReussite(chances, roll, diviseur) {
const reussite = reussites.find(x => x.condition(chances, roll));
if (diviseur > 1 && reussite.code == 'norm') {
return reussiteInsuffisante;
}
return reussite;
}
/* -------------------------------------------- */
@@ -237,7 +268,7 @@ export class RdDResolutionTable {
maxCarac = Math.min(maxCarac, minCarac + 20);
minLevel = Math.max(minLevel, -10);
maxLevel = Math.max(Math.min(maxLevel, 30), minLevel + colonnes);
return await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/resolution-table.hbs', {
return await foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/resolution-table.hbs', {
carac: carac,
difficulte: level,
min: minLevel,

View File

@@ -1,4 +1,4 @@
import { ENTITE_BLURETTE, ENTITE_INCARNE, renderTemplate } from "./constants.js";
import { ENTITE_BLURETTE, ENTITE_INCARNE } from "./constants.js";
import { RdDUtility } from "./rdd-utility.js";
/**
@@ -66,11 +66,12 @@ export class RdDEncaisser extends Dialog {
/* -------------------------------------------- */
performEncaisser(mortalite) {
this.actor.encaisserDommages({
total: Number(this.modifier),
ajustement: Number(this.modifier),
encaisserSpecial: this.encaisserSpecial,
mortalite: mortalite,
penetration: 0
dmg: {
total: Number(this.modifier),
ajustement: Number(this.modifier),
encaisserSpecial: this.encaisserSpecial,
mortalite: mortalite
}
})
}
}

View File

@@ -1,7 +1,5 @@
import { renderTemplate } from "./constants.js";
import { Misc } from "./misc.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDRollResult } from "./rdd-roll-result.js";
const titleTableDeResolution = 'Table de résolution';
/**
@@ -100,14 +98,14 @@ export class RdDRollResolutionTable extends Dialog {
async onLancer() {
await RdDResolutionTable.rollData(this.rollData);
console.log("RdDRollResolutionTable -=>", this.rollData, this.rollData.rolled);
await RdDRollResult.displayRollData(this.rollData);
await RdDResolutionTable.displayRollData(this.rollData);
}
/* -------------------------------------------- */
async onLancerFermer() {
await RdDResolutionTable.rollData(this.rollData);
console.log("RdDRollResolutionTable -=>", this.rollData, this.rollData.rolled);
await RdDRollResult.displayRollData(this.rollData);
await RdDResolutionTable.displayRollData(this.rollData);
}
/* -------------------------------------------- */

View File

@@ -1,5 +1,4 @@
import { ChatUtility } from "./chat-utility.js";
import { renderTemplate } from "./constants.js";
export class RdDRollResult {
@@ -14,6 +13,6 @@ export class RdDRollResult {
static async buildRollDataHtml(rollData, template = 'chat-resultat-general.hbs') {
rollData.show = rollData.show || {};
return await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/${template}`, rollData);
return await foundry.applications.handlebars.renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/${template}`, rollData);
}
}

View File

@@ -1,4 +1,4 @@
import { RollDataAjustements } from "./rolldata-ajustements-v1.js";
import { RollDataAjustements } from "./rolldata-ajustements.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemSort } from "./item-sort.js";
@@ -8,8 +8,7 @@ import { RdDCarac } from "./rdd-carac.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { Grammar } from "./grammar.js";
import { ACTOR_TYPES, renderTemplate } from "./constants.js";
import { EMPOIGNADE } from "./item/arme.js";
import { ACTOR_TYPES } from "./constants.js";
/**
* Extend the base Dialog entity to select roll parameters
@@ -23,7 +22,7 @@ export class RdDRoll extends Dialog {
RdDRoll._ensureCorrectAction(action);
RdDRoll._setDefaultOptions(actor, rollData);
const html = await renderTemplate(dialogConfig.html, rollData);
const html = await foundry.applications.handlebars.renderTemplate(dialogConfig.html, rollData);
let options = { classes: ["rdd-roll-dialog"], width: 650, height: 'fit-content', 'z-index': 99999, close: html => { } };
if (dialogConfig.close) {
@@ -334,8 +333,10 @@ export class RdDRoll extends Dialog {
// Mise à jour valeurs
this.html.find(".dialog-roll-title").text(this._getTitle(rollData));
this.html.find("input.check-mortalite").prop('checked', rollData.dmg.mortalite == 'non-mortel');
this.html.find("label.dmg-arme-actor").text(rollData.dmg.mortalite == EMPOIGNADE ? EMPOIGNADE : Misc.toSignedString(rollData.dmg.total));
this.html.find("label.dmg-arme-actor").text(rollData.dmg.mortalite == 'empoignade' ? 'empoignade' : Misc.toSignedString(rollData.dmg.total));
this.html.find("label.arme-mortalite").text(rollData.dmg.mortalite);
// this.html.find("[name='dmg-arme-actor']").text(rollData.dmg.mortalite == 'empoignade'? 'empoignade': Misc.toSignedString(rollData.dmg.total) );
// this.html.find("[name='arme-mortalite']").text(rollData.dmg.mortalite);
this.html.find("div.placeholder-ajustements").empty().append(adjustements);
this.html.find("div.placeholder-resolution").empty().append(resolutionTable)
}
@@ -343,7 +344,7 @@ export class RdDRoll extends Dialog {
/* -------------------------------------------- */
async buildAjustements(rollData) {
return await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.hbs`, rollData);
return await foundry.applications.handlebars.renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.hbs`, rollData);
}
/* -------------------------------------------- */

View File

@@ -1,5 +1,5 @@
import { renderTemplate, SHOW_DICE, SYSTEM_RDD } from "./constants.js";
import { RollDataAjustements } from "./rolldata-ajustements-v1.js";
import { SHOW_DICE, SYSTEM_RDD } from "./constants.js";
import { RollDataAjustements } from "./rolldata-ajustements.js";
import { RdDUtility } from "./rdd-utility.js";
import { COORD_TMR_INCONNU, TMRUtility } from "./tmr-utility.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
@@ -47,7 +47,7 @@ export class RdDTMRDialog extends Dialog {
static async create(actor, tmrData) {
await PixiTMR.init()
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.hbs', tmrData);
let html = await foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.hbs', tmrData);
if (tmrData.mode != 'visu' && !game.user.isGM) {
ChatMessage.create({ content: actor.name + " est monté dans les TMR en mode : " + tmrData.mode, whisper: ChatUtility.getGMs() });
}
@@ -508,7 +508,7 @@ export class RdDTMRDialog extends Dialog {
ChatMessage.create({
whisper: ChatUtility.getOwners(this.actor),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-rencontre-tmr.hbs`, rencData)
content: await foundry.applications.handlebars.renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-rencontre-tmr.hbs`, rencData)
});
this.$updateValuesDisplay();

View File

@@ -1,9 +1,6 @@
/* -------------------------------------------- */
import { renderTemplate } from "./constants.js";
import { HtmlUtility } from "./html-utility.js";
import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js";
import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js";
import { Targets } from "./targets.js";
/* -------------------------------------------- */
@@ -33,92 +30,47 @@ export class RdDTokenHud {
const combatant = game.combat.combatants.find(c => c.tokenId == tokenId)
const actor = RdDCombatManager.getActorCombatant(combatant, { warning: false })
if (actor) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
await RdDTokenHud.addExtensionHudCombat(html, combatant, actor, token)
}
else {
const actions = RdDCombatManager.listActionsActorCombatant(actor)
// initiative
await RdDTokenHud.addExtensionHudInit(html, combatant, actions)
// combat
await RdDTokenHud.addExtensionHudAttaques(html, combatant, token, actions.filter(it => !it.initOnly))
}
const actions = RdDCombatManager.listActionsActorCombatant(actor)
// initiative
await RdDTokenHud.addExtensionHudInit(html, combatant, actions)
// combat
await RdDTokenHud.addExtensionHudCombat(html, combatant, token, actions.filter(it => !it.initOnly))
}
}
}
static async addExtensionHudCombat(html, combatant, actor, token) {
const actionsActor = actor.listActionsCombat();
const ajustements = combatant?.initiative ?
[
{ label: 'Initiative +1', action: 'delta', value: 1 },
{ label: 'Initiative -1', action: 'delta', value: -1 }
] : []
const autres = [{ label: "Autre action", action: 'autre' }]
const actions = Misc.indexed(actionsActor.concat(ajustements).concat(autres))
const hudData = { combatant, token, actions };
const hud = $(await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/hud-actor-combat.hbs', hudData))
$(html).find('div.col.left').append(hud)
const list = hud.find('div.rdd-hud-list')
RdDTokenHud.setupHudToggle(hud, list)
const selectInitiative = list.find('select[name="initiative"]');
selectInitiative.change(event => {
const action = actions.find(it => it.index == event.currentTarget.value)
console.log('select initiative', combatant.id, action)
if (action) {
switch (action.action) {
case 'delta':
RdDCombatManager.incDecInit(combatant.id, action.value);
break
case 'autre':
RdDCombatManager.rollInitiativeAction(combatant.id,
{ label: "Autre action", action: 'autre', system: { initOnly: true, competence: "Autre action" } });
break
default:
RdDCombatManager.rollInitiativeAction(combatant.id, action)
}
selectInitiative.select("")
}
})
list.find('.rdd-attaque-v2').click(event => combatant.actor.rollAttaque(token))
}
static async addExtensionHudInit(html, combatant, actions) {
const hudData = {
combatant, actions,
commandes: [
{ label: "Autre action", command: 'autre' },
{ label: 'Initiative +1', command: 'delta', value: 1 },
{ label: 'Initiative -1', command: 'deltac', value: -1 }]
{ name: "Autre action", command: 'autre' },
{ name: 'Initiative +1', command: 'inc', value: 0.01 },
{ name: 'Initiative -1', command: 'dec', value: -0.01 }]
};
const controlIconCombat = $(html).find('.control-icon[data-action=combat]');
await RdDTokenHud._configureSubMenu(it => controlIconCombat.after(it),
await RdDTokenHud._configureSubMenu(controlIconCombat,
'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.hbs',
hudData,
(event) => {
let initCommand = event.currentTarget.attributes['data-command']?.value
let initCommandValue = Number(event.currentTarget.attributes['data-command-value']?.value ?? 0)
let combatantId = event.currentTarget.attributes['data-combatant-id']?.value
let initCommand = event.currentTarget.attributes['data-command']?.value;
let combatantId = event.currentTarget.attributes['data-combatant-id']?.value;
if (initCommand) {
RdDCombatManager.applyInitiativeCommand(combatantId, initCommand, initCommandValue)
RdDTokenHud._initiativeCommand(initCommand, combatantId);
} else {
let index = event.currentTarget.attributes['data-action-index'].value
let action = hudData.actions[index]
RdDCombatManager.rollInitiativeAction(combatantId, action)
let index = event.currentTarget.attributes['data-action-index'].value;
let action = hudData.actions[index];
RdDCombatManager.rollInitiativeAction(combatantId, action);
}
})
});
}
static async addExtensionHudAttaques(html, combatant, token, actions) {
static async addExtensionHudCombat(html, combatant, token, actions) {
const hudData = { combatant, token, actions, commandes: [] };
const divColLeft = $(html).find('div.col.left');
await RdDTokenHud._configureSubMenu(it => divColLeft.append(it),
'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.hbs',
hudData,
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];
@@ -138,7 +90,7 @@ export class RdDTokenHud {
const hudSoins = { blessures: target.actor.blessuresASoigner() ?? [] };
if (hudSoins.blessures.length > 0) {
const controlIconTarget = $(html).find('.control-icon[data-action=combat]');
await RdDTokenHud._configureSubMenu(it => controlIconTarget.after(it),
await RdDTokenHud._configureSubMenu(controlIconTarget,
'systems/foundryvtt-reve-de-dragon/templates/hud-actor-soins.hbs',
hudSoins,
(event) => {
@@ -149,6 +101,15 @@ export class RdDTokenHud {
}
}
static _initiativeCommand(initCommand, combatantId) {
switch (initCommand) {
case 'inc': return RdDCombatManager.incDecInit(combatantId, 0.01);
case 'dec': return RdDCombatManager.incDecInit(combatantId, -0.01);
case 'autre': return RdDCombatManager.rollInitiativeAction(combatantId,
{ name: "Autre action", action: 'autre', system: { initOnly: true, competence: "Autre action" } });
}
}
/* -------------------------------------------- */
static async addTokenHudExtensions(app, html, tokenId) {
console.log(`Adding token HUD extensions for token ${tokenId}`);
@@ -168,24 +129,20 @@ export class RdDTokenHud {
}
/* -------------------------------------------- */
static async _configureSubMenu(callInsertion, template, hudData, onMenuItem) {
const hud = $(await renderTemplate(template, hudData));
static async _configureSubMenu(insertionPoint, template, hudData, onMenuItem) {
const hud = $(await foundry.applications.handlebars.renderTemplate(template, hudData));
const list = hud.find('div.rdd-hud-list');
RdDTokenHud.setupHudToggle(hud, list)
RdDTokenHud._toggleHudListActive(hud, list);
hud.find('img.rdd-hud-togglebutton').click(event => RdDTokenHud._toggleHudListActive(hud, list));
list.find('.rdd-hud-menu').click(onMenuItem);
callInsertion(hud);
insertionPoint.after(hud);
}
static setupHudToggle(hud, list) {
function toggleHudList(hud, list) {
hud.toggleClass('active')
HtmlUtility.showControlWhen(list, hud.hasClass('active'))
}
toggleHudList(hud, list)
$(hud).find('img.rdd-hud-togglebutton').click(event => toggleHudList(hud, list))
static _toggleHudListActive(hud, list) {
hud.toggleClass('active');
HtmlUtility.showControlWhen(list, hud.hasClass('active'));
}
}

View File

@@ -11,6 +11,7 @@ import { RdDItem } from "./item.js";
import { RdDPossession } from "./rdd-possession.js";
import { RdDNameGen } from "./rdd-namegen.js";
import { RdDConfirm } from "./rdd-confirm.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDRaretes } from "./item/raretes.js";
@@ -18,12 +19,10 @@ import { RdDEmpoignade } from "./rdd-empoignade.js";
import { ExperienceLog } from "./actor/experience-log.js";
import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { APP_ASTROLOGIE_REFRESH } from "./sommeil/app-astrologie.js";
import { ITEM_TYPES, RDD_CONFIG, SYSTEM_RDD } from "./constants.js";
import { ITEM_TYPES, RDD_CONFIG } from "./constants.js";
import { RdDBaseActor } from "./actor/base-actor.js";
import { RdDCarac } from "./rdd-carac.js";
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
import { RdDItemCompetence } from "./item-competence.js";
import { Monnaie } from "./item-monnaie.js";
import { ItemAction } from "./item/item-actions.js";
@@ -272,13 +271,12 @@ export class RdDUtility {
// foundry et options
Handlebars.registerHelper('RDD_CONFIG', path => RDD_CONFIG[path])
Handlebars.registerHelper('settings-get', (setting) => game.settings.get(SYSTEM_RDD, setting))
Handlebars.registerHelper('linkCompendium', (pack, id, name) => RdDUtility.linkCompendium(pack, id, name));
Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionnelles.isUsing(option));
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) {
const escapedValue = RegExp.escape(Handlebars.escapeExpression(selected));
@@ -286,7 +284,7 @@ export class RdDUtility {
const html = options.fn(this);
return html.replace(rgx, "$& selected");
})
// logic
Handlebars.registerHelper('either', (a, b) => a ?? b);
// string manipulation
@@ -299,10 +297,8 @@ export class RdDUtility {
Handlebars.registerHelper('grammar-un', str => Grammar.articleIndetermine(str));
Handlebars.registerHelper('grammar-accord', (genre, ...args) => Grammar.accord(genre, args));
Handlebars.registerHelper('json-stringify', object => JSON.stringify(object))
// math
Handlebars.registerHelper('math-sum', (...values) => values.slice(0, -1).reduce(Misc.sum(), 0))
Handlebars.registerHelper('math-abs', diff => Math.abs(parseInt(diff)))
Handlebars.registerHelper('min', (...args) => Math.min(...args.slice(0, -1)));
Handlebars.registerHelper('repeat', function (n, block) {
let accum = '';
@@ -348,7 +344,7 @@ export class RdDUtility {
Handlebars.registerHelper('rarete-getChamp', (rarete, field) => RdDRaretes.getChamp(rarete, field));
Handlebars.registerHelper('item-action-applies', (action, item, options) => ItemAction.applies(action, item, options))
Handlebars.registerHelper('item-action-icon', (action, item) => ItemAction.icon(action, item))
Handlebars.registerHelper('item-name', (item) => item.nameDisplay)
Handlebars.registerHelper('item-name', (item) => item.nameDisplay)
// TMRs
Handlebars.registerHelper('caseTmr-label', coord => TMRUtility.getTMRLabel(coord));
@@ -613,33 +609,35 @@ export class RdDUtility {
/* -------------------------------------------- */
static async getLocalisation(type = 'personnage') {
const loc = { result: await RdDDice.rollTotal("1d20")};
let result = await RdDDice.rollTotal("1d20");
let txt = ""
if (type == 'personnage') {
if (loc.result <= 3) loc.txt = "Jambe, genou, pied, jarret";
else if (loc.result <= 7) loc.txt = "Hanche, cuisse, fesse";
else if (loc.result <= 9) loc.txt = "Ventre, reins";
else if (loc.result <= 12) loc.txt = "Poitrine, dos";
else if (loc.result <= 14) loc.txt = "Avant-bras, main, coude";
else if (loc.result <= 18) loc.txt = "Epaule, bras, omoplate";
else if (loc.result == 19) loc.txt = "Tête";
else if (loc.result == 20) loc.txt = "Tête (visage)";
if (result <= 3) txt = "Jambe, genou, pied, jarret";
else if (result <= 7) txt = "Hanche, cuisse, fesse";
else if (result <= 9) txt = "Ventre, reins";
else if (result <= 12) txt = "Poitrine, dos";
else if (result <= 14) txt = "Avant-bras, main, coude";
else if (result <= 18) txt = "Epaule, bras, omoplate";
else if (result == 19) txt = "Tête";
else if (result == 20) txt = "Tête (visage)";
} else {
if (loc.result <= 7) loc.txt = "Jambes/Pattes";
else if (loc.result <= 18) loc.txt = "Corps";
else if (loc.result <= 20) loc.txt = "Tête";
if (result <= 7) txt = "Jambes/Pattes";
else if (result <= 18) txt = "Corps";
else if (result <= 20) txt = "Tête";
}
return loc
return { result: result, label: txt };
}
/* -------------------------------------------- */
static async jetEncaissement(actor, dmg, armure, options = { showDice: HIDE_DICE }) {
const diff = Math.abs(dmg.diff)
const formula = RdDUtility.formuleEncaissement(diff, options)
static async jetEncaissement(actor, rollData, armure, options = { showDice: HIDE_DICE }) {
const diff = Math.abs(rollData.diffLibre);
let formula = RdDUtility.formuleEncaissement(diff, options)
const roll = await RdDDice.roll(formula, options);
RdDUtility.remplaceDeMinParDifficulte(roll, diff, options);
return await RdDUtility.prepareEncaissement(actor, dmg, roll, armure);
return await RdDUtility.prepareEncaissement(actor, rollData, roll, armure);
}
static remplaceDeMinParDifficulte(roll, diff, options) {
@@ -662,7 +660,7 @@ export class RdDUtility {
}
}
static formuleEncaissement(diff) {
static formuleEncaissement(diff, options) {
// Chaque dé fait au minimum la difficulté libre
if (ReglesOptionnelles.isUsing('degat-minimum-malus-libre')) {
return `2d10min${diff}`
@@ -671,22 +669,25 @@ export class RdDUtility {
}
/* -------------------------------------------- */
static async prepareEncaissement(actor, dmg, roll, armure) {
const jetTotal = roll.total + dmg.total - armure
const encaissement = RdDUtility._selectEncaissement(jetTotal, dmg.mortalite);
static async prepareEncaissement(actor, rollData, roll, armure) {
// La difficulté d'ataque s'ajoute aux dégâts
const bonusDegatsDiffLibre = ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(rollData.diffLibre ?? 0) : 0
const jetTotal = roll.total + rollData.dmg.total - armure + bonusDegatsDiffLibre
const encaissement = RdDUtility._selectEncaissement(jetTotal, rollData.dmg.mortalite);
const over20 = Math.max(jetTotal - 20, 0);
encaissement.dmg = dmg
encaissement.dmg = rollData.dmg
if (ReglesOptionnelles.isUsing('localisation-aleatoire')) {
encaissement.dmg.loc = dmg.loc ?? await RdDUtility.getLocalisation(actor.type)
encaissement.dmg.loc = rollData.dmg.loc ?? await RdDUtility.getLocalisation(actor.type)
encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps;'
}
else {
encaissement.dmg.loc = { label: '' }
}
encaissement.roll = roll
encaissement.armure = armure
encaissement.penetration = dmg.penetration
encaissement.total = jetTotal
encaissement.dmg.bonusDegatsDiffLibre = bonusDegatsDiffLibre
encaissement.roll = roll;
encaissement.armure = armure;
encaissement.penetration = rollData.arme?.system.penetration ?? 0;
encaissement.total = jetTotal;
encaissement.vie = await RdDUtility._evaluatePerte(encaissement.vie, over20);
encaissement.endurance = await RdDUtility._evaluatePerte(encaissement.endurance, over20);
return encaissement;

View File

@@ -1,223 +0,0 @@
import { ChatUtility } from "../chat-utility.js"
import RollDialog from "./roll-dialog.mjs"
import { RdDCarac } from "../rdd-carac.js"
import { RdDCombat } from "../rdd-combat.js"
import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs"
import { RdDResolutionTable } from "../rdd-resolution-table.js"
import { RDD_CONFIG, renderTemplate } from "../constants.js"
import { EMPOIGNADE } from "../item/arme.js"
import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js"
import { RollTypeCuisine } from "./roll-type-cuisine.mjs"
export default class ChatRollResult {
static init() {
ChatRollResult.instance = new ChatRollResult()
Hooks.on('renderChatLog', (log, html, chatLog) => ChatRollResult.instance.chatListeners(html))
}
static onReady() {
foundry.applications.handlebars.loadTemplates({
'partial-appel-chance': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-appel-chance.hbs',
'partial-attaque-particuliere': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-attaque-particuliere.hbs',
'partial-encaissement': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-encaissement.hbs',
'partial-recul-choc': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-recul-choc.hbs',
'partial-info-appel-moral': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-info-appel-moral.hbs',
})
}
async display(roll, impacts) {
this.prepareDisplay(roll)
const chatMessage = await ChatUtility.createChatWithRollMode(
{
content: await this.buildRollHtml(roll)
},
roll.active.actor,
roll.current?.rollmode?.key
)
const save = RollDialog.saveParts(roll, impacts)
ChatUtility.setMessageData(chatMessage, 'rollData', save)
return chatMessage
}
prepareDisplay(roll) {
roll.done = roll.done ?? {}
roll.show = roll.show ?? {}
roll.show.chance = this.isAppelChancePossible(roll)
roll.show.encaissement = this.isShowEncaissement(roll)
roll.show.recul = this.getRecul(roll)
//roll.show.particuliere = roll.show.particuliere ?? []
}
isAppelChancePossible(roll) {
return roll.active.actor.isPersonnage() &&
roll.rolled.isEchec &&
RdDCarac.isActionPhysique(roll.current.carac?.key)
}
isShowEncaissement(roll) {
switch (roll.type.current) {
case ROLL_TYPE_DEFENSE:
return roll.rolled.isEchec && roll.attackerRoll?.dmg.mortalite != EMPOIGNADE
}
return false
}
getRecul(roll, defender = roll.active.actor, attacker = roll.opponent?.actor) {
switch (roll.type.current) {
case ROLL_TYPE_DEFENSE:
{
const attaque = roll.attackerRoll
if (attaque &&
(roll.rolled.isEchec || !roll.current.defense.isEsquive) &&
(attaque.particuliere == 'force' || 'charge' == attaque.tactique?.key)) {
const taille = defender.system.carac.taille.value
const impact = attacker.system.carac.force.value + roll.attackerRoll?.dmg.dmgArme
return {
raison: 'charge' == attaque.tactique?.key ? 'charge' : 'particulière en force',
taille: taille,
impact: impact,
chances: RdDResolutionTable.computeChances(10, taille - impact).norm,
diff: taille - impact
}
}
break
}
case ROLL_TYPE_ATTAQUE:
{
const attaque = roll
if (attaque.particuliere == 'force' || 'charge' == attaque.tactique?.key) {
return {
raison: 'charge' == attaque.tactique?.key ? 'charge' : 'particulière en force',
}
}
}
}
return undefined
}
async buildRollHtml(roll) {
const template = `systems/foundryvtt-reve-de-dragon/templates/roll/result/chat-${roll.type.current}.hbs`
const html = await renderTemplate(template, roll)
return await RdDTextEditor.enrichHTML(html, undefined, { showLink: false })
}
async chatListeners(html) {
$(html).on("click", '.appel-chance', event => this.onClickAppelChance(event))
$(html).on("click", '.appel-destinee', event => this.onClickAppelDestinee(event))
$(html).on("click", '.encaissement', event => this.onClickEncaissement(event))
$(html).on("click", '.resister-recul', event => this.onClickRecul(event))
$(html).on("click", '.choix-particuliere', event => this.onClickChoixParticuliere(event))
$(html).on("click", '.faire-gouter', event => this.onClickFaireGouter(event))
}
getCombat(roll) {
switch (roll.type.current) {
case ROLL_TYPE_DEFENSE:
return RdDCombat.rddCombatForAttackerAndDefender(roll.ids.opponentId, roll.ids.opponentTokenId, roll.ids.actorTokenId)
case ROLL_TYPE_ATTAQUE:
return RdDCombat.rddCombatForAttackerAndDefender(roll.ids.actorId, roll.ids.actorTokenId, roll.ids.opponentId)
}
return undefined
}
async updateChatMessage(chatMessage, savedRoll) {
ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll)
const copy = foundry.utils.duplicate(savedRoll)
RollDialog.loadRollData(copy)
this.prepareDisplay(copy)
chatMessage.update({ content: await this.buildRollHtml(copy) })
chatMessage.render(true)
}
onClickAppelChance(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
const actor = game.actors.get(savedRoll.ids.actorId)
actor.rollAppelChance(
() => this.onAppelChanceSuccess(savedRoll, chatMessage),
() => this.onAppelChanceEchec(savedRoll, chatMessage))
event.preventDefault()
}
onAppelChanceSuccess(savedRoll, chatMessage) {
const reRoll = foundry.utils.duplicate(savedRoll)
console.log('onAppelChanceSuccess savedRoll', savedRoll)
reRoll.type.retry = true
const callbacks = [r => ChatUtility.removeChatMessageId(chatMessage.id)]
// TODO: annuler les effets
switch (reRoll.type.current) {
case ROLL_TYPE_DEFENSE:
this.getCombat(reRoll)?.doRollDefense(reRoll, callbacks)
break
case ROLL_TYPE_ATTAQUE:
// TODO
this.getCombat(reRoll)?.doRollAttaque(reRoll, callbacks)
break
default: {
RollDialog.create(reRoll, { callbacks: callbacks })
}
}
}
async onAppelChanceEchec(savedRoll, chatMessage) {
savedRoll.type.retry = true
await this.updateChatMessage(chatMessage, savedRoll)
}
onClickAppelDestinee(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
const actor = game.actors.get(savedRoll.ids.actorId)
actor.appelDestinee(async () => {
const reRoll = foundry.utils.duplicate(savedRoll)
reRoll.type.retry = true
RdDResolutionTable.significativeRequise(reRoll.rolled)
await this.updateChatMessage(chatMessage, reRoll)
})
}
async onClickEncaissement(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
const attaque = savedRoll.attackerRoll
const defender = game.actors.get(savedRoll.ids.actorId)
const attacker = game.actors.get(savedRoll.ids.opponentId)
const defenderToken = savedRoll.ids.actorTokenId ? canvas.tokens.get(savedRoll.ids.actorTokenId) : undefined
const attackerToken = savedRoll.ids.opponentTokenId ? canvas.tokens.get(savedRoll.ids.opponentTokenId) : undefined
await defender?.encaisserDommages(attaque.dmg, attacker, undefined, attackerToken, defenderToken)
savedRoll.done.encaissement = true
await this.updateChatMessage(chatMessage, savedRoll)
}
async onClickRecul(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
const defender = game.actors.get(savedRoll.ids.actorId)
const attacker = game.actors.get(savedRoll.ids.opponentId)
savedRoll.done.recul = await defender.encaisserRecul(attacker.getForce(), savedRoll.attackerRoll.dmg.dmgArme)
// const reculChoc = this.getReculChoc(savedRoll, defender, attacker)
await this.updateChatMessage(chatMessage, savedRoll)
}
async onClickChoixParticuliere(event) {
const choix = event.currentTarget.attributes['data-particuliere'].value
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
savedRoll.particuliere = choix
savedRoll.particulieres = [RDD_CONFIG.particuliere[choix]]
await this.updateChatMessage(chatMessage, savedRoll)
await this.getCombat(savedRoll)?.onAttaqueV2(savedRoll, callbacks)
}
async onClickFaireGouter(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
await new RollTypeCuisine().onFaireGouter(savedRoll)
}
}

View File

@@ -1,93 +1,56 @@
import { TokenActor } from "../technical/actor-token.mjs"
import { StatusEffects } from "../settings/status-effects.js"
import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs"
import { PART_ATTAQUE } from "./roll-part-attaque.mjs"
import { PART_DEFENSE } from "./roll-part-defense.mjs"
import { ActorToken } from "../actor-token.mjs"
export class RollBasicParts {
static restore(rollData) {
restore(rollData) {
rollData.ids.sceneId = rollData.ids.sceneId ?? canvas.scene.id
rollData.active = RollBasicParts.getTokenActor(rollData)
rollData.opponent = RollBasicParts.getTokenActorOpponent(rollData)
if (rollData.type.opposed == undefined) {
rollData.type.opposed = rollData.opponent != null
rollData.active = RollBasicParts.$getActor(rollData)
rollData.opponent = RollBasicParts.$getOpponent(rollData)
if (rollData.mode.opposed == undefined) {
rollData.mode.opposed = rollData.opponent != null
}
}
static loadSurprises(rollData, type = rollData.type.current) {
if (!rollData.type.passif) {
RollBasicParts.loadSurprise(rollData.active, RollBasicParts.getForceRequiseActiveActor(rollData, type))
RollBasicParts.loadSurprise(rollData.opponent, 0)
}
}
static loadSurprise(who, forceRequise) {
if (who?.actor) {
foundry.utils.mergeObject(who,
StatusEffects.getActorEffetSurprise(who.actor, forceRequise),
{ overwrite: true, inPlace: true })
}
}
static getForceRequiseActiveActor(rollData, type) {
switch (type) {
case ROLL_TYPE_ATTAQUE: return rollData.current[PART_ATTAQUE].forceRequise
case ROLL_TYPE_DEFENSE: return rollData.current[PART_DEFENSE].forceRequise
default: return 0
}
}
static initFrom(rollData) {
const isOpposed = rollData.type.opposed && rollData.opponent
initFrom(rollData) {
return {
selected: {},
type: rollData.type,
mode: {
current: rollData.mode.current
},
ids: {
sceneId: rollData.ids.sceneId,
actorId: rollData.active.id,
actorTokenId: rollData.active.tokenId,
opponentId: isOpposed ? rollData.opponent.id : undefined,
opponentTokenId: isOpposed ? rollData.opponent.tokenId : undefined,
opponentId: rollData.mode.opposed ? rollData.opponent.id : undefined,
opponentTokenId: rollData.mode.opposed ? rollData.opponent.tokenId : undefined,
}
}
}
static reverseIds(rollData) {
return {
sceneId: rollData.ids.sceneId,
actorId: rollData.ids.opponentId,
actorTokenId: rollData.ids.opponentTokenId,
opponentId: rollData.ids.actorId,
opponentTokenId: rollData.actorTokenId
}
}
static getTokenActor(rollData) {
static $getActor(rollData) {
if (rollData.ids.actorTokenId) {
return TokenActor.fromTokenId(rollData.ids.actorTokenId, rollData.ids.sceneId)
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 TokenActor.fromActorId(actorId, () => { throw new Error("Pas d'acteur sélectionné") })
return ActorToken.fromActorId(actorId, () => { throw new Error("Pas d'acteur sélectionné") })
}
}
static getTokenActorOpponent(rollData) {
static $getOpponent(rollData) {
if (rollData.ids.opponentTokenId) {
return TokenActor.fromTokenId(rollData.ids.opponentTokenId, rollData.ids.sceneId)
return ActorToken.fromTokenId(rollData.ids.opponentTokenId, rollData.ids.sceneId)
}
else if (rollData.ids.opponentId) {
return TokenActor.fromActorId(rollData.ids.opponentId)
return ActorToken.fromActorId(rollData.ids.opponentId)
}
else {
const targets = Array.from(game.user.targets)
if (targets.length == 1) {
return TokenActor.fromToken(targets[0])
return ActorToken.fromToken(targets[0])
}
else {
return undefined

View File

@@ -1,22 +1,14 @@
export const ROLL_TYPE_ATTAQUE = 'attaque'
export const ROLL_TYPE_COMP = 'comp'
export const ROLL_TYPE_CUISINE = 'cuisine'
export const ROLL_TYPE_DEFENSE = 'defense'
export const ROLL_TYPE_JEU = 'jeu'
export const ROLL_TYPE_MEDITATION = 'meditation'
export const ROLL_TYPE_OEUVRE = 'oeuvre'
export const ROLL_TYPE_SORT = 'sort'
export const ROLL_TYPE_TACHE = 'tache'
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 ATTAQUE_ROLL_TYPES = [ROLL_TYPE_ATTAQUE]
export const COMBAT_ROLL_TYPES = [ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE]
export const DEMIREVE_ROLL_TYPES = [ROLL_TYPE_SORT]
export const DEFAULT_ROLL_TYPES = [ROLL_TYPE_COMP, ROLL_TYPE_TACHE, ROLL_TYPE_MEDITATION, ROLL_TYPE_CUISINE, ROLL_TYPE_OEUVRE, ROLL_TYPE_JEU]
export const ALL_ROLL_TYPES = [...DEFAULT_ROLL_TYPES, ...COMBAT_ROLL_TYPES, ...DEMIREVE_ROLL_TYPES]
export const DIFF = {
export const DIFF_MODE = {
LIBRE: 'libre',
ATTAQUE: 'attaque',
IMPOSEE: 'imposee',
@@ -25,12 +17,12 @@ export const DIFF = {
AUCUN: 'aucun'
}
export const DIFFS = {
[DIFF.LIBRE]: { key: DIFF.LIBRE, label: "Difficulté libre", libre: true, visible: true, max: 0 },
[DIFF.ATTAQUE]: { key: DIFF.ATTAQUE, label: "Difficulté d'attaque", libre: true, visible: true, max: 0 },
[DIFF.IMPOSEE]: { key: DIFF.IMPOSEE, label: "Diffficulté imposée", libre: false, visible: true, max: 0 },
[DIFF.DEFENSE]: { key: DIFF.DEFENSE, label: "Diffficulté défense", libre: false, visible: true, max: 0 },
[DIFF.DEFAUT]: { key: DIFF.DEFAUT, label: "Difficulté", libre: true, visible: true, max: 5 },
[DIFF.AUCUN]: { key: DIFF.AUCUN, label: "", libre: false, visible: false, max: 0 },
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

@@ -4,95 +4,76 @@ 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";
import { RdDItemArme } from "../item/arme.js";
import { RdDBonus } from "../rdd-bonus.js";
import { ITEM_TYPES, RDD_CONFIG } from "../constants.js";
import { CARACS } from "../rdd-carac.js";
import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_OEUVRE } from "./roll-constants.mjs";
import { PART_ATTAQUE } from "./roll-part-attaque.mjs";
/* -------------------------------------------- */
export class RollDialogAdapter {
static async rollDice(rollData, rollTitle) {
const chances = RollDialogAdapter.computeChances({
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 RollDialogAdapter.rollChances(rollData, chances)
RollDialogAdapter.setRollDataRolled(rollData, rolled, rollTitle)
RollDialogAdapter.adjustRollDataForV1(rollData)
RollDialogAdapter.adjustAttaqueParticuliere(rollData)
const rolled = await this.rollChances(rollData, chances)
this.adjustRollDataForV1(rollData, rolled, rollTitle)
return rolled
}
static computeChances({ carac, diff, bonus, showDice, rollMode }) {
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
}
static async rollChances(rollData, chances) {
const rolled = await RdDResolutionTable.rollChances(chances,
rollData.current.sign.diviseur,
rollData.current.resultat)
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)
if (ReglesOptionnelles.isUsing("afficher-colonnes-reussite")) {
rolled.niveauNecessaire = RdDResolutionTable.findNiveauNecessaire(rolled.caracValue, rolled.roll)
rolled.ajustementNecessaire = rolled.niveauNecessaire - diff
}
return rolled
}
static setRollDataRolled(rollData, rolled, rollTitle) {
rollData.rolled = rolled
rollData.choix = rollData.choix ?? {}
rollData.show = rollData.show ?? {}
rollData.show.title = rollTitle
}
static adjustRollDataForV1(rollData) {
const rolled = rollData.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.getCaracByName(rollData.current.carac.key)
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.type.jetResistance
rollData.jetResistance = rollData.mode.jetResistance
}
if (rollData.type.current == ROLL_TYPE_OEUVRE) {
const oeuvreKey = rollData.current.oeuvre?.key
if (rollData.type.current == ROLL_TYPE_OEUVRE && oeuvreKey) {
const oeuvreCurrent = rollData.current[PART_OEUVRE];
rollData.oeuvre = oeuvreCurrent.oeuvre
rollData.art = oeuvreCurrent.art.type
}
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 = RdDResolutionTable.findNiveauNecessaire(rollData.selectedCarac.value, rolled.roll)
rolled.niveauNecessaire = this.findNiveauNecessaire(carac, rolled.roll)
rolled.ajustementNecessaire = rolled.niveauNecessaire - diff
}
rollData.ajustements = rollData.ajustements.map(aj => {
@@ -103,62 +84,7 @@ export class RollDialogAdapter {
descr: aj.diff == undefined ? aj.label : undefined
}
})
rollData.show.title = rollTitle
}
static adjustAttaqueParticuliere(rollData) {
if (rollData.type.current != ROLL_TYPE_ATTAQUE || !rollData.rolled.isPart) {
return
}
const attaque = rollData.current.attaque;
const choix = []
const isEmpoignade = attaque.dmg.mortalite == 'empoignade';
const isCharge = attaque.tactique == 'charge'
/* TODO: cas de créatures faisant des lancers, Glou, Glipzouk */
const isMeleeDiffNegative = (attaque.comp.type == ITEM_TYPES.competencecreature || rollData.current.carac.key == CARACS.MELEE)
&& rollData.current.diff.value < 0
// force toujours, sauf empoignade
if (!isEmpoignade) {
choix.push(RDD_CONFIG.particuliere.force)
}
// finesse seulement en mélée, pour l'empoignade, ou si la difficulté libre est de -1 minimum
if (!isCharge && (isEmpoignade || isMeleeDiffNegative)) {
choix.push(RDD_CONFIG.particuliere.finesse)
}
// rapidité seulement en mêlée, si l'arme le permet, et si la difficulté libre est de -1 minimum
if (!isCharge && !isEmpoignade && isMeleeDiffNegative && attaque.arme.system.rapide) {
choix.push(RDD_CONFIG.particuliere.rapidite)
}
if (choix.length == 1) {
rollData.particuliere = choix[0].key
}
rollData.particulieres = choix
}
static mapActionAttaque(attackerRoll) {
if (attackerRoll.ids) {
return attackerRoll.current[PART_ATTAQUE]
}
const label = attackerRoll.alias + ' ' + attackerRoll.arme.name;
return {
// correspond à l'attaque de RollPartAttaque (dans rollDta.current.attaque)
label: label,
// correspond aux actions d'attaques dans RdDActor.listActionsAttaque
name: label,
// action: 'attaque',
arme: attackerRoll.arme,
comp: attackerRoll.competence,
main: RdDItemArme.getMainAttaque(attackerRoll.competence),
equipe: attackerRoll.arme.system.equipe,
// carac: { key: caracCode, value: caracValue },
// dommagesArme: dommagesArme,
diff: attackerRoll.diffLibre,
particuliere: attackerRoll.particuliere,
tactique: RdDBonus.find(attackerRoll.tactique),
dmg: attackerRoll.dmg,
}
}
}

View File

@@ -1,18 +1,18 @@
import { Misc } from "../misc.js";
import { RollTypeComp } from "./roll-type-comp.mjs";
import { RollTypeTache } from "./roll-type-tache.mjs";
import { RollTypeAttaque } from "./roll-type-attaque.mjs";
import { RollTypeDefense } from "./roll-type-defense.mjs";
import { RollTypeMeditation } from "./roll-type-meditation.mjs";
import { RollTypeSort } from "./roll-type-sort.mjs";
import { RollTypeOeuvre } from "./roll-type-oeuvre.mjs";
import { RollTypeJeu } from "./roll-type-jeu.mjs";
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 { PART_CARAC, RollPartCarac } from "./roll-part-carac.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";
@@ -25,7 +25,7 @@ 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 { PART_TRICHER, RollPartTricher } from "./roll-part-tricher.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";
@@ -37,31 +37,27 @@ 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_TYPE_COMP } from "./roll-constants.mjs";
import ChatRollResult from "./chat-roll-result.mjs";
import { renderTemplate } from "../constants.js";
import { RollTypeCuisine } from "./roll-type-cuisine.mjs";
import { RollPartCuisine } from "./roll-part-cuisine.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2_TEST } from "../settings/options-avancees.js";
import { ActorImpacts } from "../technical/actor-impacts.mjs";
import { ROLL_MODE_COMP } from "./roll-constants.mjs";
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api
const doNothing = (dialog) => { }
const ALL_ROLL_TYPES = [
new RollTypeComp(),
new RollTypeTache(),
new RollTypeAttaque(),
new RollTypeDefense(),
new RollTypeSort(),
new RollTypeMeditation(),
new RollTypeCuisine(),
new RollTypeOeuvre(),
new RollTypeJeu(),
// new RollTypeResistance ??
// new RollTypeFixedCarac ??
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(),
@@ -75,7 +71,6 @@ const ROLL_PARTS = [
new RollPartMeditation(),
new RollPartSort(),
new RollPartTache(),
new RollPartCuisine(),
new RollPartOeuvre(),
new RollPartJeu(),
@@ -100,7 +95,7 @@ const ROLL_PARTS = [
* @extends {Dialog}
* # Principes
* - une seule fenêtre de dialogue (classe RollDialog)
* - plusieurs "types"s de fonctionnement (classe RollType)
* - 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
@@ -111,15 +106,15 @@ const ROLL_PARTS = [
* - 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 ?
*
* ## Types de fonctionnement - RollType
* ## Modes de fonctionnement - RollMode
*
* Un type de fonctionnement (RollType) détermine quelles parties (RollPart) de la
* 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 type de fonctionnement peut impacter les RollPart utilisés, les données
* - chaque mode de fonctionnement peut impacter les RollPart utilisés, les données
* attendues et ajoutées au rollData.
* - chaque type de fonctionnement peut définir le template de ChatMessage correspondant
* - Le type de fonctionnement détermine aussi quelles sont les effets du jet:
* - 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
@@ -173,14 +168,6 @@ const ROLL_PARTS = [
/* -------------------------------------------- */
export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2)
{
static onRollDoneDoNothing(dialog) {
dialog.render()
}
static onRollDoneClose(dialog) {
if (!OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST))
dialog.close()
}
static init() {
}
@@ -189,16 +176,14 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
foundry.applications.handlebars.loadTemplates({
'roll-section': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-section.hbs',
'roll-type': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-type.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',
})
ChatRollResult.onReady()
foundry.applications.handlebars.loadTemplates(ALL_ROLL_TYPES.map(m => m.template))
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())
@@ -232,7 +217,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
})
}
static async create(rollData, rollOptions = {}) {
const rollDialog = new RollDialog(rollData, rollOptions)
rollDialog.render(true)
@@ -262,97 +247,77 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
// rien pour l'instant
}
/** pre-configure les paramètres des différentes parties de la fenêtre (par exemple, prépare les listes de caractéristiques/compétences */
static $prepareRollData(rollData) {
rollData.current = rollData.current ?? {}
rollData.selected = rollData.selected ?? {}
rollData.type = rollData.type ?? {}
rollData.type.retry = rollData.type.retry ?? false
RollBasicParts.restore(rollData)
const potential = ALL_ROLL_TYPES.find(m => m.code == rollData.type.current)?.code
const allowed = rollData.type.retry && potential
? [potential]
: (rollData.type.allowed ?? ALL_ROLL_TYPES.filter(m => m.isAllowed(rollData) && m.visible(rollData)).map(m => m.code) ?? [ROLL_TYPE_COMP])
const rollType = allowed.find(c => c == rollData.type.current) ?? allowed[0]
rollData.type.allowed = allowed
rollData.type.current = rollType
ALL_ROLL_TYPES.find(m => m.code == rollType).setRollDataType(rollData)
rollData.refs = foundry.utils.mergeObject(rollData.refs ?? {}, Object.fromEntries(ROLL_PARTS.map(p => [p.code, {}])));
rollData.options = rollData.options ?? { rollMode: game.settings.get("core", "rollMode") }
ROLL_PARTS.forEach(p => p.initialize(rollData))
ROLL_PARTS.filter(p => p.isValid(rollData))
.forEach(p => {
p.restore(rollData)
p.loadRefs(rollData)
p.prepareContext(rollData)
})
return rollData
}
static saveParts(rollData, impacts) {
const target = RollBasicParts.initFrom(rollData)
ROLL_PARTS.filter(p => p.isActive(rollData))
.forEach(p => p.storeClean(rollData, target))
target.attackerRoll = rollData.attackerRoll
target.rolled = rollData.rolled
target.result = rollData.result
target.done = rollData.done ?? {}
target.dmg = rollData.dmg
if (impacts) {
target.reverse = {
active: impacts.active?.reverseImpacts(),
opponent: impacts.opponent?.reverseImpacts()
}
}
return target
}
constructor(rollData, rollOptions) {
super()
this.rollData = RollDialog.$prepareRollData(rollData)
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 r => await r.active.actor.appliquerAjoutExperience(r),
async r => await r.active.actor.appliquerAppelMoral(r),
async (actor, r) => await actor.appliquerAjoutExperience(r),
async (actor, r) => await actor.appliquerAppelMoral(r),
...(rollOptions.callbacks ?? [])
],
customChatMessage: rollOptions.customChatMessage,
onRollDone: rollOptions.onRollDone ?? RollDialog.onRollDoneDoNothing
onRoll: rollOptions.onRoll ?? doNothing
}
this.chatRollResult = new ChatRollResult();
this.selectType()
this.$loadParts()
}
selectType() {
const selectedType = this.getSelectedType();
this.rollData.type.label = selectedType.title(this.rollData)
selectedType.setRollDataType(this.rollData)
selectedType.onSelect(this.rollData)
/** 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;
rollData.current = rollData.current ?? {}
rollData.selected = rollData.selected ?? {}
rollData.mode = rollData.mode ?? {}
rollData.mode.retry = rollData.mode.retry ?? false
BASIC_PARTS.restore(rollData)
ROLL_PARTS.find(it => it.code == PART_CARAC).filterCaracs(this.rollData)
ROLL_PARTS.find(it => it.code == PART_COMP).filterComps(this.rollData)
const loadedMode = ROLL_MODE_TABS.find(m => m.code == rollData.mode?.current)?.code
const allowedModes = ROLL_MODE_TABS.filter(m => m.isAllowed(rollData) && m.visible(rollData)).map(m => m.code)
rollData.mode.allowed = rollData.mode.retry ? [loadedMode] : rollData.mode.allowed ?? ROLL_MODE_TABS.map(m => m.code)
rollData.mode.current = allowedModes.find(m => m == rollData.mode?.current) ?? (allowedModes.length > 0 ? allowedModes[0] : 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();
}
static getActiveParts(rollData) {
return ROLL_PARTS.filter(p => p.isActive(rollData))
selectMode() {
this.rollData.mode.label = this.getSelectedMode().title(this.rollData)
this.getSelectedMode().setRollDataMode(this.rollData)
this.getSelectedMode().onSelect(this.rollData);
}
rollTitle(rollData) {
const title = rollData.label ?? ROLL_PARTS
.filter(it => it.section == ROLLDIALOG_SECTION.ACTION)
.filter(it => it.isActive(rollData))
.map(it => it.title(rollData))
.reduce(Misc.joining(' '));
if (this.rollOptions.title) {
return `${this.rollOptions.title} ${title}`
}
return title
$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) {
@@ -364,54 +329,54 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
this.roll()
}
)
const buttonsType = this.element.querySelectorAll(`button[name="roll-type"]`)
buttonsType?.forEach(it => it.addEventListener(
const buttonsMode = this.element.querySelectorAll(`button[name="roll-mode"]`)
buttonsMode?.forEach(it => it.addEventListener(
"click", e => {
e.preventDefault()
this.rollData.type.current = e.currentTarget.dataset.type
this.selectType()
this.rollData.mode.current = e.currentTarget.dataset.mode
this.selectMode()
this.render()
}
))
Promise.all(
RollDialog.getActiveParts(this.rollData).map(async p => await p._onRender(this, context, options))
this.getActiveParts().map(async p => await p._onRender(this, context, options))
)
}
static getAjustements(rollData) {
return RollDialog.getActiveParts(rollData)
.map(p => p.getAjustements(rollData))
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 renderTemplate('roll-table', { carac, diff })
return await foundry.applications.handlebars.renderTemplate('roll-table', { carac, diff })
}
async _prepareContext() {
const rollData = this.rollData
const types = ALL_ROLL_TYPES.filter(m => m.isAllowed(rollData) && m.visible(rollData))
.map(m => m.toTypeData(rollData))
RollBasicParts.loadSurprises(rollData, this.getSelectedType().code)
rollData.type.label = this.getSelectedType()?.title(rollData)
//TOCHECK: set type.label ?
const visibleRollParts = RollDialog.getActiveParts(rollData)
visibleRollParts.forEach(p => p.applyExternalImpacts(visibleRollParts, 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))
RollDialog.calculAjustements(rollData)
this.calculAjustements()
const templates = RollDialog.getActiveParts(rollData).map(p => p.toTemplateData())
const templates = this.getActiveParts().map(p => p.toTemplateData())
const context = await super._prepareContext()
return foundry.utils.mergeObject(
{
types: types,
modes: modes,
templates: templates,
rollData: rollData,
}, context)
@@ -421,66 +386,58 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
const specialComp = visibleRollParts.map(p => p.getSpecialComp(this.rollData))
.reduce((a, b) => a.concat(b))
if (specialComp.length > 0) {
const rollPartComp = RollDialog.getActiveParts(this.rollData)
const rollPartComp = this.getActiveParts()
.find(it => it.code == PART_COMP);
rollPartComp?.setSpecialComp(this.rollData, specialComp)
}
}
static calculAjustements(rollData) {
rollData.ajustements = RollDialog.getAjustements(rollData)
rollData.ajustements.forEach(it => it.isDiff = it.diff != undefined)
rollData.current.totaldiff = rollData.ajustements
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)
}
getSelectedType() {
return ALL_ROLL_TYPES.find(m => m.code == this.rollData.type.current)
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() {
const roll = RollDialog.saveParts(this.rollData)
this.loadRollData(roll)
const selectedRollType = this.getSelectedType(roll);
selectedRollType.onSelect(roll)
roll.current.resultat = this.rollData.current[PART_TRICHER]?.resultat ?? -1
roll.choix = {}
roll.rolled = await RollDialogAdapter.rollDice(roll, this.rollTitle(roll))
const impacts = {
active: new ActorImpacts(roll.active),
opponent: roll.opponent ? new ActorImpacts(roll.opponent) : undefined
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)
}
roll.result = selectedRollType.getResult(roll, impacts)
console.info('RollDialog.roll:', roll)
const callbacks = [
...this.rollOptions.callbacks,
...selectedRollType.callbacks(this.rollOptions),
]
await Promise.all(callbacks.map(async callback => await callback(roll)))
await impacts.active?.applyImpacts()
await impacts.opponent?.applyImpacts()
selectedRollType.onApplyImpacts(roll, impacts)
await this.chatRollResult.display(roll, impacts)
this.rollOptions.onRollDone(this)
this.rollOptions.onRoll(this)
}
loadRollData(roll) {
RollDialog.$prepareRollData(roll)
RollDialog.calculAjustements(roll)
roll.v2 = true
async defaultCallback(rollData, rolled) {
await rollData.active.actor.appliquerAjoutExperience(rollData)
await rollData.active.actor.appliquerAppelMoral(rollData)
}
async defaultCallback(roll, rolled) {
await roll.active.actor.appliquerAjoutExperience(roll)
await roll.active.actor.appliquerAppelMoral(roll)
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

@@ -8,12 +8,12 @@ export class RollPartAction extends RollPart {
get section() { return ROLLDIALOG_SECTION.ACTION }
title(rollData) {
return rollData.type.label
return rollData.mode.label
}
prepareContext(rollData) {
const current = this.getCurrent(rollData)
current.verb = rollData.type.label
current.verb = rollData.mode.label
}
}

View File

@@ -10,8 +10,10 @@ export class RollPartAstrologique extends RollPartCheckbox {
get useCheckboxTemplate() { return false }
visible(rollData) {
return this.$isUsingAstrologie()
&& (this.isJetChance(rollData) || this.isLancementRituel(rollData))
return this.$isUsingAstrologie() && (
this.isJetChance(rollData)
|| this.isLancementRituel(rollData)
)
}
isLancementRituel(rollData) {

View File

@@ -1,21 +1,26 @@
import { Grammar } from "../grammar.js"
import { RdDBonus } from "../rdd-bonus.js"
import { DIFF, ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs"
import { StatusEffects } from "../settings/status-effects.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 { PART_DIFF } from "./roll-part-diff.mjs"
import { RollPartSelect } from "./roll-part-select.mjs"
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
export const PART_ATTAQUE = 'attaque'
const TACTIQUES = RdDBonus.tactiques.filter(it => it.isTactique)
const TACTIQUES = [
{ key: "", label: "Attaque normale" },
{ key: "charge", label: "Charge" },
{ key: "feinte", label: "Feinte" },
]
export class RollPartAttaque extends RollPartSelect {
get code() { return PART_ATTAQUE }
get section() { return ROLLDIALOG_SECTION.CHOIX }
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_ATTAQUE) }
visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_ATTAQUE) }
loadRefs(rollData) {
const refs = this.getRefs(rollData)
@@ -23,67 +28,55 @@ export class RollPartAttaque extends RollPartSelect {
refs.attaques = attaques.map(it => RollPartAttaque.$extractAttaque(it, rollData.active.actor))
refs.tactiques = TACTIQUES
if (refs.attaques.length > 0) {
const attaque = this.findAttaque(refs.attaques, this.getSaved(rollData))
this.$selectAttaque(rollData, attaque?.key)
this.$selectAttaque(rollData)
}
}
store(rollData, targetData) {
super.store(rollData, targetData)
this.getSaved(targetData).dmg = this.getCurrent(rollData).dmg
}
restore(rollData) {
const saved = this.getSaved(rollData)
super.restore(rollData)
if (saved.dmg) {
this.getCurrent(rollData).dmg = this.getSaved(rollData).dmg
}
}
findAttaque(attaques, saved) {
return attaques.find(at => at.arme.id == saved?.arme?.id &&
at.comp.id == saved?.comp?.id
)
}
choices(refs) { return refs.attaques }
static $extractAttaque(attaque, actor) {
// const extracted = foundry.utils.mergeObject({
// key: `${attaque.action}::${attaque.label}`,
// tactique: TACTIQUES[0]
// },
// attaque
// )
// return extracted
// extracted.initialDiff = attaque.comp?.system.default_diffLibre ?? 0
attaque.key = `${attaque.action}::${attaque.label}`
attaque.tactique = TACTIQUES[0]
attaque.initialDiff = attaque.comp?.system.default_diffLibre ?? 0
return attaque
static $extractAttaque(action, actor) {
return {
key: `${action.action}::${action.name}`,
label: action.name,
action: action,
tactique: "",
arme: action.arme,
comp: action.comp,
}
}
prepareContext(rollData) {
const current = this.getCurrent(rollData)
current.dmg = RdDBonus.dmgRollV2(rollData, current)
const defenseurSurpris = rollData.opponent?.actor?.getSurprise(true) ?? ''
current.defenseur = defenseurSurpris
? {
surprise: RdDBonus.find(defenseurSurpris),
effects: rollData.opponent.actor.getEffects(it => StatusEffects.niveauSurprise(it, true) > 0)
}
: undefined
current.dmg = this.dmgRollV2(rollData, current)
}
getAjustements(rollData) {
const current = this.getCurrent(rollData)
const ajustements = []
if (current.tactique) {
ajustements.push({ label: current.tactique.label, diff: current.tactique.attaque })
dmgRollV2(rollData, current) {
const actor = rollData.active.actor
const defender = rollData.opponent.actor
const dmgArme = RdDBonus.dmgArme(current.arme, current.action.dommagesArme)
const dmg = {
total: 0,
dmgArme: dmgArme,
penetration: current.arme.penetration(),
dmgTactique: RdDBonus.dmgBonus(current.tactique),
dmgParticuliere: 0, // TODO RdDBonus._dmgParticuliere(rollData),
dmgSurprise: RdDBonus.dmgBonus(current.defenseur.surprise),
mortalite: RdDBonus.mortalite(current.dmg?.mortalite, current.arme.system.mortalite, defender?.isEntite()),
dmgActor: RdDBonus.bonusDmg(actor, current.action.carac.key, dmgArme)
}
if (rollData.opponent?.surprise) {
ajustements.push({ label: rollData.opponent.surprise.label, diff: rollData.opponent.surprise.attaque })
}
return ajustements
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere
return dmg;
}
$selectAttaque(rollData, key) {
this.selectByKey(rollData, key)
this.selectByKey(rollData, key, 0)
}
async _onRender(rollDialog, context, options) {
@@ -96,13 +89,14 @@ export class RollPartAttaque extends RollPartSelect {
const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex
this.$selectAttaque(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.setModeTitle()
rollDialog.render()
})
selectTactique.addEventListener("change", e => {
const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex
current.tactique = RdDBonus.find(selectOptions[index]?.value)
current.tactique = TACTIQUES[index].key
rollDialog.render()
})
@@ -112,20 +106,16 @@ export class RollPartAttaque extends RollPartSelect {
})
}
impactOtherPart(part, rollData) {
getExternalPartsFilter(partCode, rollData) {
if (this.visible(rollData)) {
const current = this.getCurrent(rollData)
switch (part.code) {
case PART_CARAC: return part.filterCaracs(rollData, [current.carac.key])
case PART_COMP: return part.filterComps(rollData, [current.comp.name])
case PART_DIFF: {
if (current.initialDiff) {
part.setDiff(rollData, { type: DIFF.ATTAQUE, value: current.initialDiff })
current.initialDiff = undefined
}
}
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

@@ -36,14 +36,9 @@ export class RollPartCarac extends RollPartSelect {
}
}
filterCaracs(rollData, allowed = []) {
allowed = allowed.filter(it => it != undefined)
setFilter(rollData, filter) {
const refs = this.getRefs(rollData)
refs.caracs = allowed.length > 0
// ? refs.all.filter(it => allowed.includes(Grammar.toLowerCaseNoAccent(it.key)))
? refs.all.filter(it => allowed.includes(it.key))
: refs.all
this.$selectCarac(rollData)
refs.caracs = refs.all.filter(filter)
}
prepareContext(rollData) {

View File

@@ -28,7 +28,9 @@ export class RollPartCheckbox extends RollPart {
/* TODO: user setting? */
current.checked = true
}
current.value = this.getCheckboxValue(rollData)
if (current.value == undefined) {
current.value = this.getCheckboxValue(rollData)
}
current.icon = this.getCheckboxIcon(rollData)
}

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