Compare commits

..

1 Commits

Author SHA1 Message Date
0d24dcd9bf Nouveau roll-dialog: mode attaque 2025-09-21 00:15:36 +02:00
127 changed files with 1210 additions and 2605 deletions

View File

@@ -12,8 +12,8 @@ Pseudo : LeRatierBretonnien
Mainteneur/Développeur : LeRatierBretonnien Mainteneur/Développeur : LeRatierBretonnien
Développeur : VincentVk Développeur : VincentVk
Tests, Compendiums, Données: Fred, Fab, Grendel, LeRatierBretonnien, VincentVk Tests, Compendiums, Données: Fred, Fab, Grendel
Styles/CSS : Mandar, VincentVk Styles/CSS : Mandar
# Mentions Légales # 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. 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 !! 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. L'ensemble du code est sous licence Creative Commons.

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

@@ -3,28 +3,11 @@
## 13.0.9 - Le combat d'Illysis ## 13.0.9 - Le combat d'Illysis
- Fix - Fix
- La montée en TMR fonctionne - 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 - 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 - avancement du mode attaque
- choix de tactique - choix de tactique
- choix mortel/non-mortel pour les dommages - choix des dommages, affichage
- affichage des dommages ajustés delon les choix - affichage de la surprise du défenseur
- 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, ...)
## 13.0.8 - Le renouveau d'Illysis ## 13.0.8 - Le renouveau d'Illysis

View File

@@ -424,7 +424,7 @@ select,
.system-foundryvtt-reve-de-dragon .roll-dialog { .system-foundryvtt-reve-de-dragon .roll-dialog {
font-family: CaslonAntique; font-family: CaslonAntique;
display: grid; 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; grid-template-columns: 2rem 1rem 1fr 1fr 2fr 2fr 3fr;
gap: 0.2rem; gap: 0.2rem;
} }
@@ -450,7 +450,7 @@ select,
grid-area: resolution; grid-area: resolution;
} }
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions { .system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions {
grid-area: conditions; grid-area: modifiers;
} }
.system-foundryvtt-reve-de-dragon .roll-dialog roll-chances { .system-foundryvtt-reve-de-dragon .roll-dialog roll-chances {
grid-area: chances; grid-area: chances;
@@ -461,26 +461,26 @@ select,
.system-foundryvtt-reve-de-dragon .roll-dialog roll-buttons { .system-foundryvtt-reve-de-dragon .roll-dialog roll-buttons {
grid-area: buttons; grid-area: buttons;
} }
.system-foundryvtt-reve-de-dragon .roll-dialog roll-type { .system-foundryvtt-reve-de-dragon .roll-dialog roll-mode {
grid-area: type; grid-area: mode;
display: flex; display: flex;
flex-direction: column; 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-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); background-color: var(--color-text-selection-bg);
color: var(--color-controls); 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-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); 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-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); 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-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; height: 1.8rem;
width: 1.8rem; width: 1.8rem;
gap: 0.5rem; gap: 0.5rem;
@@ -489,11 +489,11 @@ select,
color: var(--color-controls); 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-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); 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-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); filter: invert(0.8);
} }
.system-foundryvtt-reve-de-dragon .roll-dialog :is(roll-carac, roll-comp) { .system-foundryvtt-reve-de-dragon .roll-dialog :is(roll-carac, roll-comp) {
@@ -556,17 +556,6 @@ select,
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.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 { .system-foundryvtt-reve-de-dragon .roll-dialog roll-section selected-numeric-value {
display: flow; display: flow;
width: 2.5rem; width: 2.5rem;
@@ -655,80 +644,6 @@ select,
width: 1.5rem; width: 1.5rem;
text-align: center; text-align: center;
} }
.system-foundryvtt-reve-de-dragon .chat-message 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 {
grid-area: img;
display: flex;
flex-direction: column;
}
.system-foundryvtt-reve-de-dragon .chat-message 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 {
grid-area: header;
font-weight: bold;
font-size: 0.9rem;
}
.system-foundryvtt-reve-de-dragon .chat-message 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 {
grid-area: details;
text-align: justify;
display: flex;
flex-direction: column;
}
.system-foundryvtt-reve-de-dragon .chat-message 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 {
display: flex;
flex-direction: row;
}
.system-foundryvtt-reve-de-dragon .chat-message 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 {
grid-area: buttons;
display: flex;
flex-direction: column;
}
.system-foundryvtt-reve-de-dragon .chat-message 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 {
max-width: 1rem;
max-height: 1rem;
}
.system-foundryvtt-reve-de-dragon .chat-message 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 {
position: relative;
top: 1px;
}
.system-foundryvtt-reve-de-dragon .window-header { .system-foundryvtt-reve-de-dragon .window-header {
background: rgba(0, 0, 0, 0.75); background: rgba(0, 0, 0, 0.75);
} }
@@ -1017,18 +932,16 @@ select,
} }
.system-foundryvtt-reve-de-dragon .flex-grow, .system-foundryvtt-reve-de-dragon .flex-grow,
.system-foundryvtt-reve-de-dragon .flex-grow-3 { .system-foundryvtt-reve-de-dragon .flex-grow-3 {
display: flex;
flex-grow: 3; flex-grow: 3;
} }
.system-foundryvtt-reve-de-dragon .flex-grow-0-5 { .system-foundryvtt-reve-de-dragon .flex-grow-2 {
flex-grow: 0.5; flex-grow: 2;
} }
.system-foundryvtt-reve-de-dragon .flex-grow-1 { .system-foundryvtt-reve-de-dragon .flex-grow-1 {
flex-grow: 1; flex-grow: 1;
} }
.system-foundryvtt-reve-de-dragon .flex-grow-2 { .system-foundryvtt-reve-de-dragon .flex-grow-0-5 {
display: flex; flex-grow: 0.5;
flex-grow: 2;
} }
.system-foundryvtt-reve-de-dragon .voyage-liste-survies { .system-foundryvtt-reve-de-dragon .voyage-liste-survies {
max-width: 12rem; max-width: 12rem;
@@ -1071,16 +984,14 @@ select,
justify-content: center; justify-content: center;
text-align: 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; margin: 0;
flex-grow: 1.2; flex-grow: 2;
align-items: end; align-items: end;
justify-content: flex-end; justify-content: flex-end;
text-align: right; 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 { .system-foundryvtt-reve-de-dragon .blessure-control {
flex-grow: 1; flex-grow: 1;
flex-direction: row; flex-direction: row;
@@ -1314,6 +1225,15 @@ select,
margin-right: 0.2rem; margin-right: 0.2rem;
margin-left: 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 { .system-foundryvtt-reve-de-dragon fieldset {
border-style: groove; border-style: groove;
border-width: 0.1rem; border-width: 0.1rem;
@@ -2060,13 +1980,11 @@ select,
flex-grow: 2; flex-grow: 2;
} }
.system-foundryvtt-reve-de-dragon #sidebar { .system-foundryvtt-reve-de-dragon #sidebar {
font-size: 1rem;
background: #695541 url(../assets/ui/bg_sid_dark.webp) no-repeat right bottom; background: #695541 url(../assets/ui/bg_sid_dark.webp) no-repeat right bottom;
background-position: 100%; background-position: 100%;
color: rgba(220, 220, 220, 0.75); 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 #sidebar-tabs > .collapsed,
.system-foundryvtt-reve-de-dragon #chat-controls .chat-control-icon { .system-foundryvtt-reve-de-dragon #chat-controls .chat-control-icon {
color: rgba(220, 220, 220, 0.75); color: rgba(220, 220, 220, 0.75);
@@ -2677,22 +2595,6 @@ select,
border: 2px ridge #846109; border: 2px ridge #846109;
display: inline-block; 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 { .system-foundryvtt-reve-de-dragon .chat-card-button {
text-shadow: 1px 1px #4d3534; text-shadow: 1px 1px #4d3534;
box-shadow: inset 1x 1px #a6827e; box-shadow: inset 1x 1px #a6827e;

View File

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

View File

@@ -7,7 +7,6 @@
@import "item/munition.less"; @import "item/munition.less";
@import "item/tarot.less"; @import "item/tarot.less";
@import "roll-dialog.less"; @import "roll-dialog.less";
@import "roll-chat.less";
.window-header{ .window-header{
background: rgba(0,0,0,0.75); background: rgba(0,0,0,0.75);
} }
@@ -334,18 +333,16 @@
flex-shrink: 0; flex-shrink: 0;
} }
.flex-grow, .flex-grow-3 { .flex-grow, .flex-grow-3 {
display: flex;
flex-grow: 3; flex-grow: 3;
} }
.flex-grow-0-5 { .flex-grow-2 {
flex-grow: 0.5; flex-grow: 2;
} }
.flex-grow-1 { .flex-grow-1 {
flex-grow: 1; flex-grow: 1;
} }
.flex-grow-2 { .flex-grow-0-5 {
display: flex; flex-grow: 0.5;
flex-grow: 2;
} }
.voyage-liste-survies { .voyage-liste-survies {
max-width: 12rem; max-width: 12rem;
@@ -389,16 +386,14 @@
justify-content: center; justify-content: center;
text-align: center; text-align: center;
} }
:is(.item-actions-controls, .equipement-actions) { .item-actions-controls,
.equipement-actions {
margin: 0; margin: 0;
flex-grow: 1.2; flex-grow: 2;
align-items: end; align-items: end;
justify-content: flex-end; justify-content: flex-end;
text-align: right; text-align: right;
} }
.liste-equipement :is(.equipement-actions, .item-actions-controls) {
flex-grow: 2;
}
.blessure-control { .blessure-control {
flex-grow: 1; 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 { fieldset {
border-style: groove; border-style: groove;
border-width: 0.1rem; border-width: 0.1rem;
@@ -1446,9 +1451,7 @@
/* ======================================== */ /* ======================================== */
/* Sidebar CSS */ /* Sidebar CSS */
#sidebar { #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: rgb(105,85,65) url(../assets/ui/bg_sid_dark.webp) no-repeat right bottom;
background-position: 100%; background-position: 100%;
color: rgba(220,220,220,0.75); color: rgba(220,220,220,0.75);
@@ -1958,22 +1961,6 @@
border: 2px ridge #846109; border: 2px ridge #846109;
display: inline-block; 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{ .chat-card-button{

View File

@@ -1,87 +0,0 @@
.chat-message {
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: grid-template-areas:
"header header header header header header header" "header header header header header header header"
"action action action action action action action" "action action action action action action action"
"type separation separation separation separation separation separation" "mode separation separation separation separation separation separation"
"type carac carac carac comp comp resume" "mode carac carac carac comp comp resume"
"type choix choix choix choix choix conditions" "mode choix choix choix choix choix modifiers"
"type resolution resolution resolution resolution resolution conditions" "mode resolution resolution resolution resolution resolution modifiers"
"type chances chances chances chances chances buttons" "mode chances chances chances chances chances buttons"
"footer footer footer footer footer footer footer"; "footer footer footer footer footer footer footer";
grid-template-columns: 2rem 1rem 1fr 1fr 2fr 2fr 3fr; grid-template-columns: 2rem 1rem 1fr 1fr 2fr 2fr 3fr;
gap: 0.2rem; gap: 0.2rem;
@@ -22,18 +22,18 @@
roll-choix { grid-area: choix; } roll-choix { grid-area: choix; }
roll-table { grid-area: resolution; } roll-table { grid-area: resolution; }
roll-conditions { grid-area: conditions; } roll-conditions { grid-area: modifiers; }
roll-chances { grid-area: chances; } roll-chances { grid-area: chances; }
roll-resume { grid-area: resume; } roll-resume { grid-area: resume; }
roll-buttons { grid-area: buttons; } roll-buttons { grid-area: buttons; }
roll-type { roll-mode {
grid-area: type; grid-area: mode;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
roll-conditions roll-section[name="rollmode"], roll-conditions roll-section[name="rollmode"],
roll-type { roll-mode {
button[data-checked="true"] { button[data-checked="true"] {
background-color: var(--color-text-selection-bg); background-color: var(--color-text-selection-bg);
color: var(--color-controls); color: var(--color-controls);
@@ -118,17 +118,6 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
span.status-surprise{
display: flex;
flex-direction: row;
flex-flow: wrap;
img {
filter: invert(0.8);
}
}
label {
align-content: center;
}
} }
} }
} }

View File

@@ -11,6 +11,7 @@ import { MAINS_DIRECTRICES } from "./actor.js";
import { RdDBaseActorReveSheet } from "./actor/base-actor-reve-sheet.js"; import { RdDBaseActorReveSheet } from "./actor/base-actor-reve-sheet.js";
import { ITEM_TYPES } from "./constants.js"; import { ITEM_TYPES } from "./constants.js";
import { RdDItem } from "./item.js"; import { RdDItem } from "./item.js";
import { RdDItemArme } from "./item/arme.js";
import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemBlessure } from "./item/blessure.js"; import { RdDItemBlessure } from "./item/blessure.js";
import { RdDEmpoignade } from "./rdd-empoignade.js"; import { RdDEmpoignade } from "./rdd-empoignade.js";
@@ -48,7 +49,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
}); });
foundry.utils.mergeObject(formData.calc, { foundry.utils.mergeObject(formData.calc, {
surenc: this.actor.computeMalusSurEncombrement(), 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), resumeBlessures: this.actor.computeResumeBlessure(this.actor.system.blessures),
caracTotal: RdDCarac.computeTotal(this.actor.system.carac, this.actor.system.beaute), caracTotal: RdDCarac.computeTotal(this.actor.system.carac, this.actor.system.beaute),
surEncombrementMessage: this.actor.isSurenc() ? "Sur-Encombrement!" : "", surEncombrementMessage: this.actor.isSurenc() ? "Sur-Encombrement!" : "",

View File

@@ -31,7 +31,7 @@ export class ActorToken {
constructor(token) { constructor(token) {
this.name = token.name ?? token.actor.name 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.actor = token.actor
this.id = token.actor?.id this.id = token.actor?.id
this.token = token this.token = token

View File

@@ -14,7 +14,7 @@ import { STATUSES } from "./settings/status-effects.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { EffetsDraconiques } from "./tmr/effets-draconiques.js"; import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
import { Draconique } from "./tmr/draconique.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 { DialogConsommer } from "./dialog-item-consommer.js";
import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js"; import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js";
import { RollDataAjustements } from "./rolldata-ajustements.js"; import { RollDataAjustements } from "./rolldata-ajustements.js";
@@ -31,8 +31,9 @@ import { ITEM_TYPES } from "./constants.js";
import { RdDBaseActorSang } from "./actor/base-actor-sang.js"; import { RdDBaseActorSang } from "./actor/base-actor-sang.js";
import { RdDCoeur } from "./coeur/rdd-coeur.js"; import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { DialogChoixXpCarac } from "./dialog-choix-xp-carac.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 { RdDItemBlessure } from "./item/blessure.js";
import { RdDItemTete } from "./item/tete.js"; import { RdDItemTete } from "./item/tete.js";
import { RdDItemSort } from "./item-sort.js"; import { RdDItemSort } from "./item-sort.js";
@@ -46,7 +47,7 @@ import { PAS_DE_DRACONIC, POSSESSION_SANS_DRACONIC } from "./item/base-items.js"
import { RdDRollResult } from "./rdd-roll-result.js"; import { RdDRollResult } from "./rdd-roll-result.js";
import { RdDInitiative } from "./initiative.mjs"; import { RdDInitiative } from "./initiative.mjs";
import RollDialog from "./roll/roll-dialog.mjs"; import RollDialog from "./roll/roll-dialog.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js"; import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js";
export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre'] export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre']
@@ -166,36 +167,52 @@ export class RdDActor extends RdDBaseActorSang {
.find(it => true) .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 */ /** Retourne une liste triée d'actions d'armes avec le split arme1 main / arme 2 main / lancer */
listActionsAttaque() { listActionsAttaque() {
const actions = [] let actions = [
const uniques = [] this.$prepareAttaqueArme(RdDItemArme.empoignade(this)),
this.$prepareAttaqueArme(RdDItemArme.corpsACorps(this)),
]
const addAttaque = (arme, main) => { const armes = this.itemTypes[ITEM_TYPES.arme]
const dommagesArme = RdDItemArme.valeurMain(arme.system.dommages, main) .filter(it => RdDItemArme.isAttaque(it))
const forceRequise = RdDItemArme.valeurMain(arme.system.force ?? 0, main) .sort(Misc.ascending(it => it.name));
const ecaillesEfficacite = arme.system.magique ? arme.system.ecaille_efficacite : 0;
const comp = this.getCompetence(RdDActor.$getCompetenceAction(arme, main)) for (const arme of armes) {
const unique = [comp.id, arme.name, dommagesArme, forceRequise, ecaillesEfficacite].join('|'); if (arme.system.unemain && arme.system.competence) {
if (uniques.includes(unique)) { actions.push(this.$prepareAttaqueArme(arme, '(1 main)'))
return }
if (arme.system.deuxmains && arme.system.competence) {
actions.push(this.$prepareAttaqueArme(arme, '(2 mains)'))
}
if (arme.system.lancer) {
actions.push(this.$prepareAttaqueArme(arme, '(lancer)'))
}
if (arme.system.tir) {
actions.push(this.$prepareAttaqueArme(arme, '(tir)'))
}
}
return actions;
} }
uniques.push(unique);
/* -------------------------------------------- */
$prepareAttaqueArme(arme, main) {
const comp = this.getCompetence(RdDActor.$getCompetenceAction(arme, main))
const caracCode = RdDActor.$getCaracAction(comp, main) const caracCode = RdDActor.$getCaracAction(comp, main)
const caracValue = this.system.carac[caracCode].value const caracValue = this.system.carac[caracCode].value
const dommages = arme.system.dommages.toString()
// TODO: déplacer sur RdDItemArme
if (arme.system.unemain && arme.system.deuxmains && !dommages.includes("/")) {
ui.notifications.info(`Les dommages de l'arme à 1/2 mains ${arme.name} ne sont pas corrects (ie sous la forme X/Y)`)
}
const tableauDommages = dommages.includes("/") ? dommages.split("/") : [dommages, dommages]
const dommagesArme = parseInt(main == '(2 mains)' ? tableauDommages[1] : tableauDommages[0])
const niveau = comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(main) ? -8 : -6) const niveau = comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(main) ? -8 : -6)
const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + ecaillesEfficacite const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + (arme.system.magique) ? arme.system.ecaille_efficacite : 0
actions.push({ return {
name: arme.name + (main ? ' ' + main : ''), name: arme.name + (main ? ' ' + main : ''),
action: 'attaque', action: 'attaque',
initOnly: false, initOnly: false,
@@ -205,24 +222,8 @@ export class RdDActor extends RdDBaseActorSang {
carac: { key: caracCode, value: caracValue }, carac: { key: caracCode, value: caracValue },
equipe: arme.system.equipe, equipe: arme.system.equipe,
dommagesArme: dommagesArme, dommagesArme: dommagesArme,
forceRequise: forceRequise,
initiative: RdDInitiative.calculInitiative(niveau, caracValue, ajustement) initiative: RdDInitiative.calculInitiative(niveau, caracValue, ajustement)
})
} }
addAttaque(RdDItemArme.empoignade(this))
addAttaque(RdDItemArme.corpsACorps(this))
this.itemTypes[ITEM_TYPES.arme]
.filter(it => it.isAttaque())
.sort(Misc.ascending(it => it.name))
.forEach(arme => {
if (arme.system.unemain && arme.system.competence) { addAttaque(arme, ATTAQUE_TYPE.UNE_MAIN) }
if (arme.system.deuxmains && arme.system.competence) { addAttaque(arme, ATTAQUE_TYPE.DEUX_MAINS) }
if (arme.system.lancer) { addAttaque(arme, ATTAQUE_TYPE.LANCER) }
if (arme.system.tir) { addAttaque(arme, ATTAQUE_TYPE.TIR) }
})
return actions
} }
static $getCaracAction(comp, main) { static $getCaracAction(comp, main) {
@@ -238,10 +239,10 @@ export class RdDActor extends RdDBaseActorSang {
static $getCompetenceAction(arme, main) { static $getCompetenceAction(arme, main) {
switch (main) { switch (main) {
case ATTAQUE_TYPE.UNE_MAIN: return arme.competence1Mains() case '(1 main)': return arme.competence1Mains()
case ATTAQUE_TYPE.DEUX_MAINS: return arme.competence2Mains() case '(2 mains)': return arme.competence2Mains()
case ATTAQUE_TYPE.LANCER: return arme.system.lancer case '(lancer)': return arme.system.lancer
case ATTAQUE_TYPE.TIR: return arme.system.tir case '(tir)': return arme.system.tir
default: return arme.system.competence default: return arme.system.competence
} }
} }
@@ -506,7 +507,7 @@ export class RdDActor extends RdDBaseActorSang {
'system.sante.fatigue.value': 0, 'system.sante.fatigue.value': 0,
'system.compteurs.ethylisme': { value: 1, nb_doses: 0, jet_moral: false } '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 this.supprimerBlessures(it => true);
await ChatMessage.create({ await ChatMessage.create({
whisper: ChatUtility.getOwners(this), whisper: ChatUtility.getOwners(this),
@@ -2277,12 +2278,13 @@ export class RdDActor extends RdDBaseActorSang {
static _getComposantsCaracDerivee(caracName) { static _getComposantsCaracDerivee(caracName) {
switch (Grammar.toLowerCaseNoAccent(caracName)) { switch (Grammar.toLowerCaseNoAccent(caracName)) {
case CARACS.REVE_ACTUEL: case 'reve actuel': return [CARACS.REVE] case 'reve-actuel': case 'reve actuel': return ['reve']
case CARACS.CHANCE_ACTUELLE: case 'chance actuelle': return [CARACS.CHANCE] case 'chance-actuelle': case 'chance actuelle': return ['chance']
case CARACS.TIR: return [CARACS.DEXTERITE, CARACS.VUE] case 'vie': return ['constitution']
case CARACS.LANCER: return [CARACS.FORCE, CARACS.DEXTERITE, CARACS.VUE] case 'tir': return ['vue', 'dexterite']
case CARACS.MELEE: return [CARACS.FORCE, CARACS.AGILITE] case 'lancer': return ['force', 'dexterite', 'vue']
case CARACS.DEROBEE: return [CARACS.AGILITE] case 'melee': return ['force', 'agilite']
case 'derobee': return ['agilite']
} }
return [] return []
} }
@@ -2513,27 +2515,29 @@ export class RdDActor extends RdDBaseActorSang {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async computeArmure(dmg) { async computeArmure(attackerRoll) {
let baseDmg = (dmg.dmgArme ?? 0) + (dmg.dmgActor ?? 0); let dmg = (attackerRoll.dmg.dmgArme ?? 0) + (attackerRoll.dmg.dmgActor ?? 0);
let armeData = attackerRoll.arme;
let protection = 0; let protection = 0;
if (dmg.encaisserSpecial != "noarmure") { const armures = this.items.filter(it => it.type == "armure" && it.system.equipe);
const armures = this.items.filter(it => it.type == "armure" && it.system.equipe)
for (const armure of armures) { for (const armure of armures) {
protection += await RdDDice.rollTotal(armure.system.protection.toString()); protection += await RdDDice.rollTotal(armure.system.protection.toString());
if (baseDmg > 0 && dmg.encaisserSpecial != "noarmure") { if (dmg > 0 && attackerRoll.dmg.encaisserSpecial != "noarmure") {
await armure.deteriorerArmure(baseDmg) await armure.deteriorerArmure(dmg)
baseDmg = 0; dmg = 0;
} }
} }
protection -= Math.min(dmg.penetration, protection) const penetration = Misc.toInt(armeData?.system.penetration ?? 0);
protection = Math.max(protection - penetration, 0);
protection += this.getProtectionNaturelle(); protection += this.getProtectionNaturelle();
// Gestion des cas particuliers sur la fenêtre d'encaissement // Gestion des cas particuliers sur la fenêtre d'encaissement
if (dmg.encaisserSpecial == "chute") { if (attackerRoll.dmg.encaisserSpecial == "noarmure") {
protection = 0;
}
if (attackerRoll.dmg.encaisserSpecial == "chute") {
protection = Math.min(protection, 2); protection = Math.min(protection, 2);
} }
} console.log("Final protect", protection, attackerRoll);
console.log("Final protect", protection, dmg)
return protection; return protection;
} }
@@ -3047,15 +3051,15 @@ 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 oeuvre = this.items.get(oeuvreId)
const rollData = { const rollData = {
title: `Interpretation de ${oeuvre.name} par ${this.name}`, title: `Interpretation de ${oeuvre.name} par ${this.name}`,
type: { mode: {
allowed: ["oeuvre"], allowed: ["oeuvre"]
current: "oeuvre",
}, },
selected: { selected: {
mode: "oeuvre",
oeuvre: { key: oeuvre.id }, oeuvre: { key: oeuvre.id },
}, },
ids: { ids: {
@@ -3063,14 +3067,24 @@ export class RdDActor extends RdDBaseActorSang {
} }
} }
await RollDialog.create(rollData, { await RollDialog.create(rollData, {
onRollDone: (dialog) => { onRoll: (dialog) => {
if (!OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST)) this._onCloseRollDialog(),
dialog.close() 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) { async rollOeuvre(id) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) { if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
return await this._rollArtV2(id) return await this._rollArtV2(id)
@@ -3156,7 +3170,7 @@ export class RdDActor extends RdDBaseActorSang {
async _resultArt(artData) { async _resultArt(artData) {
const niveau = artData.oeuvre.system.niveau ?? 0; const niveau = artData.oeuvre.system.niveau ?? 0;
const baseQualite = (artData.rolled.isSuccess ? niveau : artData.competence.system.niveau); 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`); await RdDRollResult.displayRollData(artData, this.name, `chat-resultat-${artData.art}.hbs`);
} }
@@ -3177,7 +3191,7 @@ export class RdDActor extends RdDBaseActorSang {
async _resultRecetteCuisine(cuisine) { async _resultRecetteCuisine(cuisine) {
const niveauRecette = cuisine.oeuvre.system.niveau ?? 0; const niveauRecette = cuisine.oeuvre.system.niveau ?? 0;
const baseQualite = (cuisine.rolled.isSuccess ? niveauRecette : cuisine.competence.system.niveau); 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.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) cuisine.sust = cuisine.oeuvre.system.sust * Math.min(cuisine.proportions, cuisine.proportionsMax ?? cuisine.proportions)
const platCuisine = { const platCuisine = {
@@ -3235,4 +3249,3 @@ export class RdDActor extends RdDBaseActorSang {
} }
} }

View File

@@ -14,8 +14,9 @@ import { RdDConfirm } from "../rdd-confirm.js";
import { RdDCarac } from "../rdd-carac.js"; import { RdDCarac } from "../rdd-carac.js";
import { RdDRollResult } from "../rdd-roll-result.js"; import { RdDRollResult } from "../rdd-roll-result.js";
import { RdDItemArme } from "../item/arme.js";
import { RdDItemCompetence } from "../item-competence.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 { ChatUtility } from "../chat-utility.js";
import { DialogValidationEncaissement } from "../dialog-validation-encaissement.js"; import { DialogValidationEncaissement } from "../dialog-validation-encaissement.js";
@@ -24,7 +25,6 @@ import { RdDEmpoignade } from "../rdd-empoignade.js";
import { RdDPossession } from "../rdd-possession.js"; import { RdDPossession } from "../rdd-possession.js";
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, POSSESSION_SANS_DRACONIC } from "../item/base-items.js"; import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, POSSESSION_SANS_DRACONIC } from "../item/base-items.js";
import { RollDataAjustements } from "../rolldata-ajustements.js"; import { RollDataAjustements } from "../rolldata-ajustements.js";
import { MappingCreatureArme } from "../item/mapping-creature-arme.mjs";
/** /**
* Classe de base pour les acteurs disposant de rêve (donc, pas des objets) * Classe de base pour les acteurs disposant de rêve (donc, pas des objets)
@@ -113,12 +113,13 @@ export class RdDBaseActorReve extends RdDBaseActor {
listActions({ isAttaque = false, isEquipe = false }) { listActions({ isAttaque = false, isEquipe = false }) {
return this.itemTypes[ITEM_TYPES.competencecreature] return this.itemTypes[ITEM_TYPES.competencecreature]
.filter(it => it.isAttaque()) .filter(it => RdDItemCompetenceCreature.isAttaque(it))
.map(it => it.attaqueCreature()) .map(it => RdDItemCompetenceCreature.attaqueCreature(it))
.filter(it => it != undefined); .filter(it => it != undefined);
} }
async computeArmure(dmg) { return this.getProtectionNaturelle() }
async computeArmure(attackerRoll) { return this.getProtectionNaturelle() }
async remiseANeuf() { } async remiseANeuf() { }
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { } async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { }
@@ -190,10 +191,6 @@ export class RdDBaseActorReve extends RdDBaseActor {
return RdDItemArme.getArme(armeParadeId ? this.getEmbeddedDocument('Item', armeParadeId) : undefined) return RdDItemArme.getArme(armeParadeId ? this.getEmbeddedDocument('Item', armeParadeId) : undefined)
} }
isForceInsuffisante(forceRequise) {
return false
}
getDraconicOuPossession() { return POSSESSION_SANS_DRACONIC } getDraconicOuPossession() { return POSSESSION_SANS_DRACONIC }
getPossession(possessionId) { getPossession(possessionId) {
@@ -225,13 +222,8 @@ export class RdDBaseActorReve extends RdDBaseActor {
/* -------------------------------------------- */ /* -------------------------------------------- */
isEffectAllowed(effectId) { return false } isEffectAllowed(effectId) { return false }
getEffects(filter = e => true, forceRequise = undefined) { getEffects(filter = e => true) {
const effects = this.getEmbeddedCollection("ActiveEffect") return this.getEmbeddedCollection("ActiveEffect").filter(filter);
const selected = effects.filter(filter)
if (forceRequise && this.isForceInsuffisante(forceRequise)) {
selected.push(StatusEffects.prepareActiveEffect(STATUSES.StatusForceWeak))
}
return selected
} }
getEffectByStatus(statusId) { getEffectByStatus(statusId) {
@@ -256,8 +248,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
async removeEffects(filter = e => true) { async removeEffects(filter = e => true) {
if (game.user.isGM) { if (game.user.isGM) {
const effectsToRemove = this.getEffects(filter); const ids = this.getEffects(filter).map(it => it.id);
const ids = effectsToRemove.map(it => it.id);
await this.deleteEmbeddedDocuments('ActiveEffect', ids); await this.deleteEmbeddedDocuments('ActiveEffect', ids);
} }
} }
@@ -268,7 +259,11 @@ export class RdDBaseActorReve extends RdDBaseActor {
} }
getSurprise(isCombat = undefined) { getSurprise(isCombat = undefined) {
return StatusEffects.getSurprise(this.getEffects(), isCombat) return StatusEffects.typeSurprise(
this.getEffects()
.map(it => StatusEffects.niveauSurprise(it, isCombat))
.reduce(Misc.sum(), 0)
)
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -417,7 +412,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
} }
if (competence.type == ITEM_TYPES.competencecreature) { if (competence.type == ITEM_TYPES.competencecreature) {
const token = RdDUtility.getSelectedToken(this) const token = RdDUtility.getSelectedToken(this)
const arme = MappingCreatureArme.armeCreature(competence) const arme = RdDItemCompetenceCreature.armeCreature(competence)
if (arme && options.tryTarget && Targets.hasTargets()) { if (arme && options.tryTarget && Targets.hasTargets()) {
Targets.selectOneTargetToken(target => { Targets.selectOneTargetToken(target => {
if (arme.action == "possession") { if (arme.action == "possession") {
@@ -430,7 +425,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
return; return;
} }
// Transformer la competence de créature // Transformer la competence de créature
MappingCreatureArme.setRollDataCreature(rollData) RdDItemCompetenceCreature.setRollDataCreature(rollData)
} }
const dialogLabel = 'Jet ' + Grammar.apostrophe('de', competence.name); const dialogLabel = 'Jet ' + Grammar.apostrophe('de', competence.name);
await this.openRollDialog({ await this.openRollDialog({
@@ -458,7 +453,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
token = token ?? RdDUtility.getSelectedToken(this) token = token ?? RdDUtility.getSelectedToken(this)
const compToUse = RdDItemArme.getCompetenceArme(arme, categorieArme) const compToUse = RdDItemArme.getCompetenceArme(arme, categorieArme)
if (!RdDItemArme.isUtilisable(arme)) { 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 return
} }
if (!Targets.hasTargets()) { if (!Targets.hasTargets()) {
@@ -495,37 +490,29 @@ export class RdDBaseActorReve extends RdDBaseActor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async encaisser() { await RdDEncaisser.encaisser(this) } 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')) { if (attacker && !await attacker.accorder(this, 'avant-encaissement')) {
return return;
} }
if (!Misc.isOwnerPlayer(this)) { const armure = await this.computeArmure(rollData);
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)
if (ReglesOptionnelles.isUsing('validation-encaissement-gr')) { if (ReglesOptionnelles.isUsing('validation-encaissement-gr')) {
await this.encaisserDommagesValidationGR(dmg, armure, show, attackerToken, defenderToken); await this.encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken);
} }
else { 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) 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) { if (!game.user.isGM) {
RdDBaseActor.remoteActorCall({ RdDBaseActor.remoteActorCall({
tokenId: this.token?.id, tokenId: this.token?.id,
actorId: this.id, actorId: this.id,
method: 'encaisserDommagesValidationGR', args: [dmg, armure, show, attackerToken, defenderToken] method: 'encaisserDommagesValidationGR', args: [rollData, armure, show, attackerToken, defenderToken]
}) })
} else { } else {
DialogValidationEncaissement.validerEncaissement(this, dmg, armure, DialogValidationEncaissement.validerEncaissement(this, rollData, armure,
jet => this.$onEncaissement(jet, show, attackerToken, defenderToken)); jet => this.$onEncaissement(jet, show, attackerToken, defenderToken));
} }
} }
@@ -562,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') { async accorder(entite, when = 'avant-encaissement') {
if (when != game.settings.get(SYSTEM_RDD, "accorder-entite-cauchemar") if (when != game.settings.get(SYSTEM_RDD, "accorder-entite-cauchemar")
|| entite == undefined || entite == undefined
|| !entite.isEntite([ENTITE_INCARNE]) || !entite.isEntite([ENTITE_INCARNE])
|| entite.isEntiteAccordee(this)) { || 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 = { const rollData = {
alias: this.getAlias(), alias: this.getAlias(),
rolled: rolled, rolled: rolled,
@@ -601,11 +566,11 @@ export class RdDBaseActorReve extends RdDBaseActor {
}; };
if (rolled.isSuccess) { if (rolled.isSuccess) {
await entite.setEntiteReveAccordee(this) await entite.setEntiteReveAccordee(this);
} }
await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-accorder-cauchemar.hbs') await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-accorder-cauchemar.hbs');
await this.appliquerAjoutExperience(rollData, true) await this.appliquerAjoutExperience(rollData, true);
return rolled.isSuccess; return rolled.isSuccess;
} }

View File

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

View File

@@ -9,7 +9,6 @@ import { RdDAudio } from "../rdd-audio.js";
import { RdDConfirm } from "../rdd-confirm.js"; import { RdDConfirm } from "../rdd-confirm.js";
import { RdDUtility } from "../rdd-utility.js"; import { RdDUtility } from "../rdd-utility.js";
import { SystemCompendiums } from "../settings/system-compendiums.js"; import { SystemCompendiums } from "../settings/system-compendiums.js";
import { RdDItem } from "../item.js";
export class RdDBaseActor extends Actor { export class RdDBaseActor extends Actor {
@@ -500,8 +499,7 @@ export class RdDBaseActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async computeEncTotal() { async computeEncTotal() {
if (!this.pack) { if (!this.pack) {
this.encTotal = this.items.filter(it => RdDItem.getItemTypesInventaire().includes(it.type)) this.encTotal = this.items.map(it => it.getEncTotal()).reduce(Misc.sum(), 0);
.map(it => it.getEncTotal()).reduce(Misc.sum(), 0)
return this.encTotal; return this.encTotal;
} }
return 0; return 0;

View File

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

View File

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

View File

@@ -9,7 +9,7 @@ import { RdDBonus } from "../../rdd-bonus.js"
import { TMRType } from "../../tmr-utility.js" import { TMRType } from "../../tmr-utility.js"
export const CATEGORIES_COMPETENCES_BASE = [ export const CATEGORIES_COMPETENCES = [
"generale", "generale",
"particuliere", "particuliere",
"specialisee", "specialisee",
@@ -88,7 +88,7 @@ const MAPPING_BASE = [
{ column: "endurance_actuel", rollClass: 'jet-endurance', getter: (actor, context) => actor.system.sante.endurance.value }, { column: "endurance_actuel", rollClass: 'jet-endurance', getter: (actor, context) => actor.system.sante.endurance.value },
{ column: "esquive", getter: (actor, context) => Mapping.getEsquive(context) }, { column: "esquive", getter: (actor, context) => Mapping.getEsquive(context) },
{ column: "esquive_armure", getter: (actor, context) => Mapping.getEsquiveArmure(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) }, { column: "draconic", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_DRACONIC) },
] ]

View File

@@ -197,12 +197,8 @@ export class ChatUtility {
static async onCreateChatMessage(chatMessage, options, id) { static async onCreateChatMessage(chatMessage, options, id) {
if (chatMessage.isAuthor) { 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 }) }) 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

@@ -106,14 +106,3 @@ export const ITEM_TYPES = {
nombreastral: 'nombreastral', nombreastral: 'nombreastral',
extraitpoetique: 'extraitpoetique', extraitpoetique: 'extraitpoetique',
} }
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" }
}

View File

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

View File

@@ -1,7 +1,6 @@
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { RdDItem } from "./item.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"; import { Misc } from "./misc.js";
const competenceTroncs = [["Esquive", "Dague", "Corps à corps"], 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() { function _buildCumulXP() {
let cumulXP = { "-11": 0 }; let cumulXP = { "-11": 0 };
@@ -40,12 +49,7 @@ function _buildCumulXP() {
const competence_xp_cumul = _buildCumulXP(); const competence_xp_cumul = _buildCumulXP();
export class RdDItemCompetence extends RdDItem { export class RdDItemCompetence extends Item {
static get ITEM_TYPE() { return ITEM_TYPES.competence }
static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp" }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getLabelCategorie(category) { static getLabelCategorie(category) {
return CATEGORIES_COMPETENCES[category].label; return CATEGORIES_COMPETENCES[category].label;

View File

@@ -1,49 +1,87 @@
import { ITEM_TYPES } from "./constants.js"; import { ITEM_TYPES } from "./constants.js";
import { RdDItem } from "./item.js"; import { Grammar } from "./grammar.js";
import { RdDInitiative } from "./initiative.mjs"; 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" } /* -------------------------------------------- */
static armeCreature(item) {
isParade() { return this.system.iscombat && (this.system.categorie_parade ?? '') != '' } const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(item)
isBouclier() { return this.system.categorie_parade.includes('bouclier') }
attaqueCreature() {
const categorieAttaque = this.getCategorieAttaque()
if (categorieAttaque != undefined) { if (categorieAttaque != undefined) {
const initative = RdDInitiative.calculInitiative(this.system.niveau, this.system.carac_value); // cloner pour ne pas modifier la compétence
const attaque = { return foundry.utils.mergeObject(item, {
name: this.name, action: item.isCompetencePossession() ? 'possession' : 'attaque',
action: this.isCompetencePossession() ? 'possession' : 'attaque',
initOnly: false,
arme: new RdDItemArme({
name: this.name,
type: ITEM_TYPES.arme,
img: this.img,
system: { system: {
competence: this.name, competence: item.name,
cac: categorieAttaque == "naturelle" ? "naturelle" : "", cac: categorieAttaque == "naturelle" ? "naturelle" : "",
niveau: this.system.niveau, 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, initiative: initative,
mortalite: this.system.mortalite, mortalite: comp.system.mortalite,
dommages: this.system.dommages, dommages: comp.system.dommages,
equipe: true, equipe: true,
resistance: 100, resistance: 100,
penetration: 0, penetration: 0,
force: 0, force: 0,
rapide: true, rapide: true,
} }
}), });
comp: this, const attaque = {
carac: { key: this.name, value: this.system.carac_value }, name: comp.name,
action: comp.isCompetencePossession() ? 'possession' : 'attaque',
initOnly: false,
arme: armeComp,
comp: comp,
carac: { key: comp.name, value: comp.system.carac_value },
equipe: true, equipe: true,
mortalite: this.system.mortalite, mortalite: comp.system.mortalite,
dmg: this.system.dommages, dmg: comp.system.dommages,
initiative: initative initiative: initative
}; };
return attaque return attaque
@@ -51,29 +89,42 @@ export class RdDItemCompetenceCreature extends RdDItem {
return undefined; return undefined;
} }
isAttaque() { /* -------------------------------------------- */
return this.getCategorieAttaque() != undefined static isAttaque(item) {
return RdDItemCompetenceCreature.getCategorieAttaque(item) != undefined
} }
getCategorieAttaque() { static getCategorieAttaque(item) {
switch (this.system.categorie) { if (item.type == ITEM_TYPES.competencecreature) {
switch (item.system.categorie) {
case "melee": case "melee":
case "tir": case "tir":
case "lancer": case "lancer":
case "naturelle": case "naturelle":
case "possession": case "possession":
return this.system.categorie return item.system.categorie
} }
} }
return undefined
}
isDommages() { static isDommages(item) {
switch (this.system.categorie) { if (item.type == ITEM_TYPES.competencecreature) {
switch (item.system.categorie) {
case "melee": case "melee":
case "tir": case "tir":
case "lancer": case "lancer":
case "naturelle": case "naturelle":
return true return true
} }
}
return false
}
static isParade(item) {
if (item.type == ITEM_TYPES.competencecreature) {
return item.system.categorie_parade || item.system.isparade
}
return false return false
} }

View File

@@ -1,9 +1,7 @@
import { ACTOR_TYPES, ITEM_TYPES } from "./constants.js"; import { ACTOR_TYPES, ITEM_TYPES } from "./constants.js";
import { RdDItem } from "./item.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemSort } from "./item-sort.js"; import { RdDItemSort } from "./item-sort.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { RdDItemCompetence } from "./item-competence.js";
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { SYSTEM_RDD } from "./constants.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 { SystemCompendiums } from "./settings/system-compendiums.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDTimestamp } from "./time/rdd-timestamp.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 { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js";
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js"; import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
import { ItemAction } from "./item/item-actions.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) { if (this.item.type == ITEM_TYPES.competencecreature) {
formData.isparade = this.item.isParade() formData.isparade = RdDItemCompetenceCreature.isParade(this.item)
formData.isdommages = this.item.isDommages() formData.isdommages = RdDItemCompetenceCreature.isDommages(this.item)
} }
if (this.item.type == ITEM_TYPES.tache || if (this.item.type == ITEM_TYPES.tache ||
this.item.type == ITEM_TYPES.livre || this.item.type == ITEM_TYPES.livre ||

View File

@@ -1,6 +1,4 @@
import { ITEM_TYPES } from "./constants.js"; import { ITEM_TYPES } 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 { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
@@ -9,6 +7,10 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { SystemCompendiums } from "./settings/system-compendiums.js"; import { SystemCompendiums } from "./settings/system-compendiums.js";
import { RdDRaretes } from "./item/raretes.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 = [ const typesInventaireMateriel = [
ITEM_TYPES.arme, ITEM_TYPES.arme,
@@ -184,10 +186,7 @@ export class RdDItem extends Item {
isMonnaie() { return this.type == ITEM_TYPES.monnaie; } isMonnaie() { return this.type == ITEM_TYPES.monnaie; }
isNourritureBoisson() { return this.type == ITEM_TYPES.nourritureboisson; } isNourritureBoisson() { return this.type == ITEM_TYPES.nourritureboisson; }
isService() { return this.type == ITEM_TYPES.service; } isService() { return this.type == ITEM_TYPES.service; }
isAttaque() { return false }
isParade() { return false }
isBouclier() { return false }
getCategorieAttaque() { return undefined }
isCompetence() { return typesObjetsCompetence.includes(this.type) } isCompetence() { return typesObjetsCompetence.includes(this.type) }
isEsquive() { isEsquive() {
return (this.isCompetence() return (this.isCompetence()

View File

@@ -1,9 +1,10 @@
import { ITEM_TYPES } from "../constants.js"; import { ITEM_TYPES } from "../constants.js";
import { RdDItem } from "../item.js"; import { RdDItem } from "../item.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js"
import { BASE_CORPS_A_CORPS } from "./base-items.js"; import { BASE_CORPS_A_CORPS } from "./base-items.js";
import { Grammar } from "../grammar.js"; import { Grammar } from "../grammar.js";
import { RdDInitiative } from "../initiative.mjs"; import { RdDInitiative } from "../initiative.mjs";
import { MappingCreatureArme } from "./mapping-creature-arme.mjs";
const nomCategorieParade = { const nomCategorieParade = {
"sans-armes": "Sans arme", "sans-armes": "Sans arme",
@@ -18,49 +19,28 @@ const nomCategorieParade = {
"haches": "Haches", "haches": "Haches",
"lances": "Lances", "lances": "Lances",
} }
export const ATTAQUE_TYPE = {
UNE_MAIN: '(1 main)',
DEUX_MAINS: '(2 mains)',
COMPETENCE: 'competence',
TIR: '(tir)',
LANCER: '(lancer)'
}
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDItemArme extends RdDItem { export class RdDItemArme extends RdDItem {
static get ITEM_TYPE() { return ITEM_TYPES.arme } 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) } penetration() {
return parseInt(this.system.penetration ?? 0);
isParade() { return this.system.resistance > 0 && this.system.categorie_parade } }
isBouclier() { return RdDItemArme.getCategorieParade(this).includes('bouclier') }
/* -------------------------------------------- */ /* -------------------------------------------- */
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) { static getArme(arme) {
switch (arme ? arme.type : '') { switch (arme ? arme.type : '') {
case ITEM_TYPES.arme: return arme; case ITEM_TYPES.arme: return arme;
case ITEM_TYPES.competencecreature: case ITEM_TYPES.competencecreature:
return MappingCreatureArme.armeCreature(arme); return RdDItemCompetenceCreature.armeCreature(arme);
} }
return RdDItemArme.corpsACorps(); return RdDItemArme.corpsACorps();
} }
@@ -71,11 +51,11 @@ export class RdDItemArme extends RdDItem {
return arme.name return arme.name
case ITEM_TYPES.arme: case ITEM_TYPES.arme:
switch (maniement) { switch (maniement) {
case ATTAQUE_TYPE.COMPETENCE: return arme.system.competence; case 'competence': return arme.system.competence;
case ATTAQUE_TYPE.UNE_MAIN: return arme.competence1Mains() case '(1 main)': return arme.competence1Mains()
case ATTAQUE_TYPE.DEUX_MAINS: return arme.competence2Mains() case '(2 mains)': return arme.competence2Mains()
case ATTAQUE_TYPE.TIR: case 'tir': return arme.system.tir case '(tir)': case 'tir': return arme.system.tir
case ATTAQUE_TYPE.LANCER: case 'lancer': return arme.system.lancer; case '(lancer)': case 'lancer': return arme.system.lancer;
} }
} }
return undefined return undefined
@@ -112,13 +92,16 @@ export class RdDItemArme extends RdDItem {
/* -------------------------------------------- */ /* -------------------------------------------- */
static getCategorieParade(armeData) { static getCategorieParade(armeData) {
if (![ITEM_TYPES.arme, ITEM_TYPES.competencecreature].includes(armeData.type)) {
return ''
}
if (armeData.system.categorie_parade) { if (armeData.system.categorie_parade) {
return armeData.system.categorie_parade return armeData.system.categorie_parade
} }
// pour compatibilité avec des personnages existants // 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) { if (armeData.system.competence == undefined) {
return ITEM_TYPES.competencecreature; return ITEM_TYPES.competencecreature;
} }
@@ -213,7 +196,7 @@ export class RdDItemArme extends RdDItem {
return Number(arme.system.dommages) return Number(arme.system.dommages)
} }
const tableauDegats = arme.system.dommages.split("/"); 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); return Number(arme.system.dommages);
} }
@@ -222,7 +205,7 @@ export class RdDItemArme extends RdDItem {
static armeUneOuDeuxMains(arme, aUneMain) { static armeUneOuDeuxMains(arme, aUneMain) {
if (arme && !arme.system.cac) { if (arme && !arme.system.cac) {
arme = foundry.utils.duplicate(arme); 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; return arme;
} }
@@ -243,9 +226,24 @@ export class RdDItemArme extends RdDItem {
return false return false
} }
isAttaque() { static isAttaque(arme) {
return this.system.resistance > 0 || this.system.portee_courte > 0 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 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 corpsACorps(actor) { static corpsACorps(actor) {
let competence = actor?.getCompetenceCorpsACorps() ?? BASE_CORPS_A_CORPS let competence = actor?.getCompetenceCorpsACorps() ?? BASE_CORPS_A_CORPS

View File

@@ -18,23 +18,3 @@ export const SANS_COMPETENCE = {
img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp" 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

@@ -1,42 +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.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;
}
}

View File

@@ -34,9 +34,6 @@ export class Misc {
return ((n % m) + m) % m; return ((n % m) + m) % m;
} }
static inRange(value, min,max){
return Math.max(min, Math.min(value, max))
}
static sum() { static sum() {
return (a, b) => Number(a) + Number(b); return (a, b) => Number(a) + Number(b);
} }

View File

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

View File

@@ -52,15 +52,6 @@ export const CARACS = {
EMPATHIE: 'empathie', EMPATHIE: 'empathie',
REVE: 'reve', REVE: 'reve',
CHANCE: 'chance', 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 = { export const LIST_CARAC_PERSONNAGE = {
[CARACS.TAILLE]: { code: CARACS.TAILLE, label: 'Taille', isCarac: true, path: 'system.carac.taille.value' }, [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.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.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.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' }, 'protection': { code: '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' } 'beaute': { code: 'beaute', label: 'Beauté', isCarac: false, path: 'system.background.beaute.value' }
} }
export const LIST_CARAC_AUTRES = { 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 = { const LIST_CARAC_DERIVEE = {
[CARACS.MELEE]: { code: CARACS.MELEE, label: 'Mêlée', path: 'system.carac.melee.value' }, 'melee': { code: "melee", label: 'Mêlée', path: 'system.carac.melee.value' },
[CARACS.TIR]: { code: CARACS.TIR, label: 'Tir', path: 'system.carac.tir.value' }, 'tir': { code: "tir", label: 'Tir', path: 'system.carac.tir.value' },
[CARACS.LANCER]: { code: CARACS.LANCER, label: 'Lancer', path: 'system.carac.lancer.value' }, 'lancer': { code: "lancer", label: 'Lancer', path: 'system.carac.lancer.value' },
[CARACS.DEROBEE]: { code: CARACS.DEROBEE, label: 'Dérobée', path: 'system.carac.derobee.value' }, 'derobee': { code: "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' }, 'chance-actuelle': { code: "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' }, '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') 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) { static isIntellect(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel) == CARACS.INTELLECT return Grammar.toLowerCaseNoAccent(caracLabel) == 'intellect';
} }
static isVolonte(caracLabel) { static isVolonte(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel) == CARACS.VOLONTE return Grammar.toLowerCaseNoAccent(caracLabel) == 'volonte';
} }
static isChance(caracLabel) { static isChance(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel)?.match(/chance(( |-)?actuelle)?/); return Grammar.toLowerCaseNoAccent(caracLabel)?.match(/chance(( |-)?actuelle)?/);

View File

@@ -7,18 +7,14 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDRoll } from "./rdd-roll.js"; import { RdDRoll } from "./rdd-roll.js";
import { RdDRollTables } from "./rdd-rolltables.js"; import { RdDRollTables } from "./rdd-rolltables.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { STATUSES } from "./settings/status-effects.js";
import { Targets } from "./targets.js"; import { Targets } from "./targets.js";
import { RdDEmpoignade } from "./rdd-empoignade.js"; import { RdDEmpoignade } from "./rdd-empoignade.js";
import { RdDRollResult } from "./rdd-roll-result.js"; import { RdDRollResult } from "./rdd-roll-result.js";
import { RdDItemArme } from "./item/arme.js"; import { RdDItemArme } from "./item/arme.js";
import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { RdDInitiative } from "./initiative.mjs"; import { 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_TEST } from "./settings/options-avancees.js";
import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs";
/* -------------------------------------------- */ /* -------------------------------------------- */
const premierRoundInit = [ const premierRoundInit = [
@@ -372,7 +368,7 @@ export class RdDCombat {
if (Misc.isOwnerPlayer(defender)) { if (Misc.isOwnerPlayer(defender)) {
let attackerRoll = msg.attackerRoll; let attackerRoll = msg.attackerRoll;
let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : undefined; 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); const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id);
rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme); rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
} }
@@ -402,19 +398,15 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
static registerChatCallbacks(html) { static registerChatCallbacks(html) {
for (let button of [ for (let button of [
'.button-defense', '.parer-button',
'.button-parade', '.esquiver-button',
'.button-esquive',
'.button-encaisser',
'.particuliere-attaque', '.particuliere-attaque',
'.encaisser-button',
'.appel-chance-defense', '.appel-chance-defense',
'.appel-destinee-defense', '.appel-destinee-defense',
'.appel-chance-attaque', '.appel-chance-attaque',
'.appel-destinee-attaque', '.appel-destinee-attaque',
'.echec-total-attaque', '.echec-total-attaque',
// '.appel-chance',
// '.chat-encaissement',
// '.resister-recul',
]) { ]) {
$(html).on("click", button, event => { $(html).on("click", button, event => {
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender( const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(
@@ -474,11 +466,9 @@ export class RdDCombat {
switch (button) { switch (button) {
case '.particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value); case '.particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value);
case '.button-defense': return this.defenseV2(attackerRoll); case '.parer-button': return this.parade(attackerRoll, armeParadeId);
case '.esquiver-button': return this.esquive(attackerRoll, compId, competence);
case '.button-parade': return this.parade(attackerRoll, armeParadeId); case '.encaisser-button': return this.encaisser(attackerRoll, defenderRoll);
case '.button-esquive': return this.esquive(attackerRoll, compId, competence);
case '.button-encaisser': return this.encaisser(attackerRoll, defenderRoll);
case '.echec-total-attaque': return this._onEchecTotal(attackerRoll); case '.echec-total-attaque': return this._onEchecTotal(attackerRoll);
case '.appel-chance-attaque': return this.attacker.rollAppelChance( case '.appel-chance-attaque': return this.attacker.rollAppelChance(
@@ -488,9 +478,11 @@ export class RdDCombat {
() => this.defenseChanceuse(attackerRoll, defenderRoll), () => this.defenseChanceuse(attackerRoll, defenderRoll),
() => this.afficherOptionsDefense(attackerRoll, defenderRoll, { defenseChance: true })); () => this.afficherOptionsDefense(attackerRoll, defenderRoll, { defenseChance: true }));
case '.appel-destinee-attaque': return this.attacker.appelDestinee( case '.appel-destinee-attaque': return this.attacker.appelDestinee(
() => this.attaqueSignificative(attackerRoll)); () => this.attaqueSignificative(attackerRoll),
() => { });
case '.appel-destinee-defense': return this.defender.appelDestinee( case '.appel-destinee-defense': return this.defender.appelDestinee(
() => this.defenseDestinee(defenderRoll)); () => this.defenseDestinee(defenderRoll),
() => { });
} }
} }
@@ -560,42 +552,27 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
static isEchecTotal(rollData) { static isEchecTotal(rollData) {
if (rollData.ids /* roll V2*/) { if (!rollData.attackerRoll && rollData.ajustements.surprise.used) {
// TODO: en cas de demi-surprise à l'attaque, tout échec est un echec total. return rollData.rolled.isEchec && rollData.rolled.code != 'notSign';
// TODO: en cas de demi-surprise en défense, pas de changement à la règle de base
return rollData.rolled.isETotal
} }
if (rollData.mode == ROLL_TYPE_ATTAQUE && rollData.surprise == 'demi') { return rollData.rolled.isETotal;
// échec normal à l'attaque en demi surprise
return rollData.rolled.isEchec && rollData.rolled.code != 'notSign'
}
return rollData.rolled.isETotal
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static isParticuliere(rollData) { static isParticuliere(rollData) {
if (rollData.ids /* roll V2*/) { if (!rollData.attackerRoll && rollData.ajustements.surprise.used) {
return rollData.rolled.isPart return false;
} }
if (rollData.attackerRoll || !rollData.ajustements.surprise.used) { return rollData.rolled.isPart;
return rollData.rolled.isPart
}
return false
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static isReussite(rollData) { 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) { switch (rollData.ajustements.surprise.used) {
case 'totale': return false case 'totale': return false;
case 'demi': return rollData.rolled.isSign case 'demi': return rollData.rolled.isSign;
} }
return rollData.rolled.isSuccess return rollData.rolled.isSuccess;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -702,7 +679,6 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
_prepareAttaque(competence, arme) { _prepareAttaque(competence, arme) {
let rollData = { let rollData = {
mode: ROLL_TYPE_ATTAQUE,
alias: this.attacker?.getAlias(), alias: this.attacker?.getAlias(),
passeArme: foundry.utils.randomID(16), passeArme: foundry.utils.randomID(16),
mortalite: arme?.system.mortalite, mortalite: arme?.system.mortalite,
@@ -715,7 +691,7 @@ export class RdDCombat {
}; };
if (this.attacker.isCreatureEntite()) { if (this.attacker.isCreatureEntite()) {
MappingCreatureArme.setRollDataCreature(rollData); RdDItemCompetenceCreature.setRollDataCreature(rollData);
} }
else if (arme) { else if (arme) {
// Usual competence // Usual competence
@@ -737,6 +713,9 @@ export class RdDCombat {
if (RdDCombat.isReussite(attackerRoll)) { if (RdDCombat.isReussite(attackerRoll)) {
return await this._onAttaqueNormale(attackerRoll) return await this._onAttaqueNormale(attackerRoll)
} }
// if (RdDCombat.isParticuliere(attackerRoll) && attackerRoll.particuliere == undefined) {
// return
// }
if (RdDCombat.isEchecTotal(attackerRoll)) { if (RdDCombat.isEchecTotal(attackerRoll)) {
return await this._onAttaqueEchecTotal(attackerRoll) return await this._onAttaqueEchecTotal(attackerRoll)
} }
@@ -807,6 +786,8 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
async _sendMessageDefense(attackerRoll, defenderRoll, essaisPrecedents = undefined) { 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); this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
if (essaisPrecedents) { if (essaisPrecedents) {
foundry.utils.mergeObject(attackerRoll.essais, essaisPrecedents, { overwrite: true }); foundry.utils.mergeObject(attackerRoll.essais, essaisPrecedents, { overwrite: true });
@@ -876,7 +857,7 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
_filterArmesParade(defender, competence, armeAttaque) { _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 = foundry.utils.duplicate(defenses)
defenses.forEach(armeDefense => { defenses.forEach(armeDefense => {
// Ajout du # d'utilisation ce round // Ajout du # d'utilisation ce round
@@ -898,7 +879,6 @@ export class RdDCombat {
const choixEchecTotal = await ChatMessage.create({ const choixEchecTotal = await ChatMessage.create({
whisper: ChatUtility.getOwners(this.attacker), whisper: ChatUtility.getOwners(this.attacker),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.hbs', { content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.hbs', {
rolled: attackerRoll.rolled,
attackerId: this.attackerId, attackerId: this.attackerId,
attacker: this.attacker, attacker: this.attacker,
attackerToken: this.attackerToken, attackerToken: this.attackerToken,
@@ -966,46 +946,9 @@ export class RdDCombat {
dialog.render(true); dialog.render(true);
} }
async defenseV2(attackerRoll) {
// this._prepareParade(attackerRoll, arme, competence);
await this.doRollDefense({
ids: {
actorId: this.defender.id,
actorTokenId: this.defenderTokenId,
opponentTokenId: this.attackerTokenId,
opponentId: this.attackerId,
},
type: { allowed: ['defense'], current: 'defense' },
attackerRoll: RollDialogAdapter.mapActionAttaque(attackerRoll),
passeArme: attackerRoll.passeArme,
})
}
async doRollDefense(rollData, callbacks = []) {
await RollDialog.create(rollData, {
onRollDone: (dialog) => {
if (!OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST))
dialog.close()
},
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) { _prepareParade(attackerRoll, armeParade, competenceParade) {
let defenderRoll = { let defenderRoll = {
mode: ROLL_TYPE_DEFENSE,
alias: this.defender?.getAlias(), alias: this.defender?.getAlias(),
passeArme: attackerRoll.passeArme, passeArme: attackerRoll.passeArme,
diffLibre: attackerRoll.diffLibre, diffLibre: attackerRoll.diffLibre,
@@ -1022,52 +965,12 @@ export class RdDCombat {
}; };
if (this.defender.isCreatureEntite()) { if (this.defender.isCreatureEntite()) {
MappingCreatureArme.setRollDataCreature(defenderRoll); RdDItemCompetenceCreature.setRollDataCreature(defenderRoll);
} }
return 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._onDefenseParticuliere(rollData, isEsquive)
}
}
this.removeChatMessageActionsPasseArme(rollData.passeArme)
}
async _onDefenseParticuliere(rollData, isEsquive) {
if (isEsquive) {
ChatUtility.createChatWithRollMode(
{ content: "<strong>Vous pouvez esquiver une deuxième fois!</strong>" },
this.defender)
}
else 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) { async _onParade(defenderRoll) {
if (RdDCombat.isReussite(defenderRoll)) { if (RdDCombat.isReussite(defenderRoll)) {
@@ -1139,7 +1042,6 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
_prepareEsquive(attackerRoll, competence) { _prepareEsquive(attackerRoll, competence) {
let rollData = { let rollData = {
mode: ROLL_TYPE_DEFENSE,
alias: this.defender.getAlias(), alias: this.defender.getAlias(),
passeArme: attackerRoll.passeArme, passeArme: attackerRoll.passeArme,
diffLibre: attackerRoll.diffLibre, diffLibre: attackerRoll.diffLibre,
@@ -1154,7 +1056,7 @@ export class RdDCombat {
}; };
if (this.defender.isCreatureEntite()) { if (this.defender.isCreatureEntite()) {
MappingCreatureArme.setRollDataCreature(rollData); RdDItemCompetenceCreature.setRollDataCreature(rollData);
} }
return rollData; return rollData;
} }
@@ -1203,7 +1105,7 @@ export class RdDCombat {
// Est-ce une parade normale? // Est-ce une parade normale?
if (defenderRoll.arme && attackerRoll && !defenderRoll.rolled.isPart) { if (defenderRoll.arme && attackerRoll && !defenderRoll.rolled.isPart) {
// Est-ce que l'attaque est une particulière en force ou une charge // 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 || {} defenderRoll.show = defenderRoll.show || {}
@@ -1251,7 +1153,7 @@ export class RdDCombat {
finalLevel: Misc.toInt(defenderRoll.competence.system.niveau) - dmg, finalLevel: Misc.toInt(defenderRoll.competence.system.niveau) - dmg,
showDice: HIDE_DICE showDice: HIDE_DICE
}); });
defenderRoll.show.desarme = desarme.rolled.isEchec defenderRoll.show.desarme = desarme.rolled.isEchec;
} }
} }
} }
@@ -1259,19 +1161,41 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
async computeRecul(defenderRoll) { // Calcul du recul (p. 132) async computeRecul(defenderRoll) { // Calcul du recul (p. 132)
if (!ReglesOptionnelles.isUsing('recul')) {
return
}
const attackerRoll = defenderRoll.attackerRoll; const attackerRoll = defenderRoll.attackerRoll;
if (this._isForceOuCharge(attackerRoll, defenderRoll.v2)) { if (ReglesOptionnelles.isUsing('recul') && this._isForceOuCharge(attackerRoll)) {
defenderRoll.show.recul = this.defender.encaisserRecul(this.attacker.getForce(), attackerRoll.dmg.dmgArme) 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) { async encaisser(attackerRoll, defenderRoll) {
@@ -1281,16 +1205,12 @@ export class RdDCombat {
this._onEchecTotal(defenderRoll); this._onEchecTotal(defenderRoll);
} }
await this.doRollEncaissement(attackerRoll, defenderRoll);
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
}
async doRollEncaissement(attackerRoll, defenderRoll) {
if (Misc.isOwnerPlayer(this.defender)) { if (Misc.isOwnerPlayer(this.defender)) {
attackerRoll.attackerId = this.attackerId; attackerRoll.attackerId = this.attackerId;
attackerRoll.defenderTokenId = this.defenderToken.id; attackerRoll.defenderTokenId = this.defenderToken.id;
await this.computeRecul(defenderRoll); 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 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, { game.socket.emit(SYSTEM_SOCKET_ID, {
@@ -1301,8 +1221,9 @@ export class RdDCombat {
attackerToken: this.attackerToken, attackerToken: this.attackerToken,
defenderToken: this.defenderToken defenderToken: this.defenderToken
} }
}) });
} }
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -1335,4 +1256,3 @@ export class RdDCombat {
}) })
} }
} }

View File

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

View File

@@ -1,4 +1,5 @@
import { ATTAQUE_TYPE, RdDItemArme } from "./item/arme.js"; import { RdDItemArme } from "./item/arme.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { ITEM_TYPES } from "./constants.js"; import { ITEM_TYPES } from "./constants.js";
export class RdDHotbar { export class RdDHotbar {
@@ -19,13 +20,10 @@ export class RdDHotbar {
await game.user.assignHotbarMacro(macro, slot); await game.user.assignHotbarMacro(macro, slot);
} }
static $macroNameSuffix(maniement) { static $macroNameSuffix(armeCompetence) {
switch (maniement) { switch (armeCompetence) {
case ATTAQUE_TYPE.UNE_MAIN: case '(1 main)': return ' (1 main)';
case ATTAQUE_TYPE.DEUX_MAINS: case '(2 mains)': return ' (2 main)';
case ATTAQUE_TYPE.LANCER:
case ATTAQUE_TYPE.TIR:
return ' ' + maniement
case 'tir': return ' (tir)'; case 'tir': return ' (tir)';
case 'lancer': return ' (lancer)'; case 'lancer': return ' (lancer)';
case 'pugilat': return ' (pugilat)'; case 'pugilat': return ' (pugilat)';
@@ -41,22 +39,22 @@ export class RdDHotbar {
// Les armes peuvent avoir plusieurs usages // Les armes peuvent avoir plusieurs usages
if (item.system.competence != '') { if (item.system.competence != '') {
if (item.system.unemain) { if (item.system.unemain) {
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.UNE_MAIN) await this.createItemMacro(item, slot++, '(1 main)')
} }
if (item.system.deuxmains) { if (item.system.deuxmains) {
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.DEUX_MAINS) await this.createItemMacro(item, slot++, '(2 mains)')
} }
} }
if (item.system.lancer != '') { if (item.system.lancer != '') {
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.LANCER) await this.createItemMacro(item, slot++, 'lancer')
} }
if (item.system.tir != '') { if (item.system.tir != '') {
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.TIR) await this.createItemMacro(item, slot++, 'lancer')
} }
} }
return return
case ITEM_TYPES.competencecreature: case ITEM_TYPES.competencecreature:
const categorie = item.getCategorieAttaque() ?? 'competence'; const categorie = RdDItemCompetenceCreature.getCategorieAttaque(item) ?? 'competence';
await this.createItemMacro(item, slot, categorie) await this.createItemMacro(item, slot, categorie)
return return
default: default:
@@ -129,7 +127,7 @@ export class RdDHotbar {
} }
return actor.rollCompetence(item); return actor.rollCompetence(item);
case ITEM_TYPES.competencecreature: case ITEM_TYPES.competencecreature:
return item.system.iscombat return item.system.iscombat && !item.system.isparade
? actor.rollArme(item, categorieArme) ? actor.rollArme(item, categorieArme)
: actor.rollCompetence(item); : actor.rollCompetence(item);

View File

@@ -45,8 +45,6 @@ import * as sheets from "./applications/sheets/_module.mjs"
import { RdDItemArme } from "./item/arme.js" import { RdDItemArme } from "./item/arme.js"
import { RdDItemArmure } from "./item/armure.js" import { RdDItemArmure } from "./item/armure.js"
import { RdDItemBlessure } from "./item/blessure.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 { RdDItemGemme } from "./item/gemme.js"
import { RdDItemMaladie } from "./item/maladie.js" import { RdDItemMaladie } from "./item/maladie.js"
import { RdDItemOmbre } from "./item/ombre.js" import { RdDItemOmbre } from "./item/ombre.js"
@@ -88,7 +86,6 @@ import { RdDCombatManager, RdDCombat } from "./rdd-combat.js"
import { Migrations } from './migrations.js' import { Migrations } from './migrations.js'
import RollDialog from "./roll/roll-dialog.mjs" import RollDialog from "./roll/roll-dialog.mjs"
import ChatRollResult from "./roll/chat-roll-result.mjs"
/** /**
* RdD system * RdD system
@@ -115,8 +112,6 @@ export class SystemReveDeDragon {
arme: RdDItemArme, arme: RdDItemArme,
armure: RdDItemArmure, armure: RdDItemArmure,
blessure: RdDItemBlessure, blessure: RdDItemBlessure,
competence: RdDItemCompetence,
competencecreature: RdDItemCompetenceCreature,
gemme: RdDItemGemme, gemme: RdDItemGemme,
maladie: RdDItemMaladie, maladie: RdDItemMaladie,
ombre: RdDItemOmbre, ombre: RdDItemOmbre,
@@ -297,7 +292,6 @@ export class SystemReveDeDragon {
TMRRencontres.init() TMRRencontres.init()
ExportScriptarium.init() ExportScriptarium.init()
RollDialog.init() RollDialog.init()
ChatRollResult.init()
} }
initSettings() { 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() { async onReady() {
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Foundry VTT Initialization */ /* Foundry VTT Initialization */
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -371,8 +376,7 @@ export class SystemReveDeDragon {
StatusEffects.onReady() StatusEffects.onReady()
RdDDice.onReady() RdDDice.onReady()
RollDialog.onReady() RollDialog.onReady()
ChatRollResult.onReady() RdDStatBlockParser.parseStatBlock()
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Affiche/Init le calendrier */ /* Affiche/Init le calendrier */
game.system.rdd.calendrier.display() game.system.rdd.calendrier.display()
@@ -385,17 +389,7 @@ export class SystemReveDeDragon {
}) })
} }
this.setupAccueil() SystemReveDeDragon.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();
}
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

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

View File

@@ -157,7 +157,7 @@ export class RdDResolutionTable {
/* -------------------------------------------- */ /* -------------------------------------------- */
static significativeRequise(chances) { 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 }); foundry.utils.mergeObject(chances, reussites.find(x => x.code == 'sign'), { overwrite: true });
} }
@@ -184,15 +184,47 @@ export class RdDResolutionTable {
return Math.max(Math.floor(carac * (diff + 10) / 2), 1); return Math.max(Math.floor(carac * (diff + 10) / 2), 1);
} }
/* -------------------------------------------- */
static isEchec(rollData) {
switch (rollData.surprise) {
case 'demi': return !rollData.rolled.isSign;
case 'totale': return true;
}
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) { static computeReussite(chances, roll, diviseur) {
const reussite = reussites.find(x => x.condition(chances, roll)) const reussite = reussites.find(x => x.condition(chances, roll));
if (diviseur > 1 && reussite.isSuccess) { if (diviseur > 1 && reussite.code == 'norm') {
if (chances > roll * diviseur) { return reussiteInsuffisante;
return reussiteInsuffisante
} }
} return reussite;
return reussite
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@@ -66,11 +66,12 @@ export class RdDEncaisser extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
performEncaisser(mortalite) { performEncaisser(mortalite) {
this.actor.encaisserDommages({ this.actor.encaisserDommages({
dmg: {
total: Number(this.modifier), total: Number(this.modifier),
ajustement: Number(this.modifier), ajustement: Number(this.modifier),
encaisserSpecial: this.encaisserSpecial, encaisserSpecial: this.encaisserSpecial,
mortalite: mortalite, mortalite: mortalite
penetration: 0 }
}) })
} }
} }

View File

@@ -9,7 +9,6 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { ACTOR_TYPES } from "./constants.js"; import { ACTOR_TYPES } from "./constants.js";
import { RdDUtility } from "./rdd-utility.js";
/** /**
* Extend the base Dialog entity to select roll parameters * Extend the base Dialog entity to select roll parameters

View File

@@ -11,6 +11,7 @@ import { RdDItem } from "./item.js";
import { RdDPossession } from "./rdd-possession.js"; import { RdDPossession } from "./rdd-possession.js";
import { RdDNameGen } from "./rdd-namegen.js"; import { RdDNameGen } from "./rdd-namegen.js";
import { RdDConfirm } from "./rdd-confirm.js"; import { RdDConfirm } from "./rdd-confirm.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDRaretes } from "./item/raretes.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 { ExperienceLog } from "./actor/experience-log.js";
import { RdDCoeur } from "./coeur/rdd-coeur.js"; import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { APP_ASTROLOGIE_REFRESH } from "./sommeil/app-astrologie.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 { RdDBaseActor } from "./actor/base-actor.js";
import { RdDCarac } from "./rdd-carac.js"; import { RdDCarac } from "./rdd-carac.js";
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js"; import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
import { RdDItemCompetence } from "./item-competence.js";
import { Monnaie } from "./item-monnaie.js"; import { Monnaie } from "./item-monnaie.js";
import { ItemAction } from "./item/item-actions.js"; import { ItemAction } from "./item/item-actions.js";
@@ -272,7 +271,6 @@ export class RdDUtility {
// foundry et options // foundry et options
Handlebars.registerHelper('RDD_CONFIG', path => RDD_CONFIG[path]) 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('linkCompendium', (pack, id, name) => RdDUtility.linkCompendium(pack, id, name));
Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionnelles.isUsing(option)); Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionnelles.isUsing(option));
@@ -611,33 +609,35 @@ export class RdDUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async getLocalisation(type = 'personnage') { static async getLocalisation(type = 'personnage') {
const loc = { result: await RdDDice.rollTotal("1d20")}; let result = await RdDDice.rollTotal("1d20");
let txt = ""
if (type == 'personnage') { if (type == 'personnage') {
if (loc.result <= 3) loc.txt = "Jambe, genou, pied, jarret"; if (result <= 3) txt = "Jambe, genou, pied, jarret";
else if (loc.result <= 7) loc.txt = "Hanche, cuisse, fesse"; else if (result <= 7) txt = "Hanche, cuisse, fesse";
else if (loc.result <= 9) loc.txt = "Ventre, reins"; else if (result <= 9) txt = "Ventre, reins";
else if (loc.result <= 12) loc.txt = "Poitrine, dos"; else if (result <= 12) txt = "Poitrine, dos";
else if (loc.result <= 14) loc.txt = "Avant-bras, main, coude"; else if (result <= 14) txt = "Avant-bras, main, coude";
else if (loc.result <= 18) loc.txt = "Epaule, bras, omoplate"; else if (result <= 18) txt = "Epaule, bras, omoplate";
else if (loc.result == 19) loc.txt = "Tête"; else if (result == 19) txt = "Tête";
else if (loc.result == 20) loc.txt = "Tête (visage)"; else if (result == 20) txt = "Tête (visage)";
} else { } else {
if (loc.result <= 7) loc.txt = "Jambes/Pattes"; if (result <= 7) txt = "Jambes/Pattes";
else if (loc.result <= 18) loc.txt = "Corps"; else if (result <= 18) txt = "Corps";
else if (loc.result <= 20) loc.txt = "Tête"; else if (result <= 20) txt = "Tête";
} }
return loc
return { result: result, label: txt };
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async jetEncaissement(actor, dmg, armure, options = { showDice: HIDE_DICE }) { static async jetEncaissement(actor, rollData, armure, options = { showDice: HIDE_DICE }) {
const diff = Math.abs(dmg.diff) const diff = Math.abs(rollData.diffLibre);
const formula = RdDUtility.formuleEncaissement(diff, options) let formula = RdDUtility.formuleEncaissement(diff, options)
const roll = await RdDDice.roll(formula, options); const roll = await RdDDice.roll(formula, options);
RdDUtility.remplaceDeMinParDifficulte(roll, diff, 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) { static remplaceDeMinParDifficulte(roll, diff, options) {
@@ -660,7 +660,7 @@ export class RdDUtility {
} }
} }
static formuleEncaissement(diff) { static formuleEncaissement(diff, options) {
// Chaque dé fait au minimum la difficulté libre // Chaque dé fait au minimum la difficulté libre
if (ReglesOptionnelles.isUsing('degat-minimum-malus-libre')) { if (ReglesOptionnelles.isUsing('degat-minimum-malus-libre')) {
return `2d10min${diff}` return `2d10min${diff}`
@@ -669,22 +669,25 @@ export class RdDUtility {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async prepareEncaissement(actor, dmg, roll, armure) { static async prepareEncaissement(actor, rollData, roll, armure) {
const jetTotal = roll.total + dmg.total - armure // La difficulté d'ataque s'ajoute aux dégâts
const encaissement = RdDUtility._selectEncaissement(jetTotal, dmg.mortalite); 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); const over20 = Math.max(jetTotal - 20, 0);
encaissement.dmg = dmg encaissement.dmg = rollData.dmg
if (ReglesOptionnelles.isUsing('localisation-aleatoire')) { 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;' encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps;'
} }
else { else {
encaissement.dmg.loc = { label: '' } encaissement.dmg.loc = { label: '' }
} }
encaissement.roll = roll encaissement.dmg.bonusDegatsDiffLibre = bonusDegatsDiffLibre
encaissement.armure = armure encaissement.roll = roll;
encaissement.penetration = dmg.penetration encaissement.armure = armure;
encaissement.total = jetTotal encaissement.penetration = rollData.arme?.system.penetration ?? 0;
encaissement.total = jetTotal;
encaissement.vie = await RdDUtility._evaluatePerte(encaissement.vie, over20); encaissement.vie = await RdDUtility._evaluatePerte(encaissement.vie, over20);
encaissement.endurance = await RdDUtility._evaluatePerte(encaissement.endurance, over20); encaissement.endurance = await RdDUtility._evaluatePerte(encaissement.endurance, over20);
return encaissement; return encaissement;

View File

@@ -1,180 +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"
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-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) {
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)
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.getReculChoc(roll)
}
isAppelChancePossible(roll) {
return roll.active.actor.isPersonnage() &&
roll.rolled.isEchec &&
RdDCarac.isActionPhysique(roll.current.carac?.key)
}
isShowEncaissement(roll) {
return roll.rolled.isEchec &&
roll.attackerRoll?.dmg.mortalite != 'empoignade'
}
getReculChoc(roll, defender = roll.active.actor, attacker = roll.opponent.actor) {
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
}
}
return undefined
}
async buildRollHtml(roll) {
const template = `systems/foundryvtt-reve-de-dragon/templates/roll/result/chat-${roll.type.current}.hbs`
return await foundry.applications.handlebars.renderTemplate(template, roll)
}
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))
}
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)
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)
}
}

View File

@@ -1,8 +1,4 @@
import { ActorToken } from "../actor-token.mjs" import { ActorToken } from "../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"
export class RollBasicParts { export class RollBasicParts {
@@ -10,44 +6,23 @@ export class RollBasicParts {
rollData.ids.sceneId = rollData.ids.sceneId ?? canvas.scene.id rollData.ids.sceneId = rollData.ids.sceneId ?? canvas.scene.id
rollData.active = RollBasicParts.$getActor(rollData) rollData.active = RollBasicParts.$getActor(rollData)
rollData.opponent = RollBasicParts.$getOpponent(rollData) rollData.opponent = RollBasicParts.$getOpponent(rollData)
if (rollData.type.opposed == undefined) { if (rollData.mode.opposed == undefined) {
rollData.type.opposed = rollData.opponent != null rollData.mode.opposed = rollData.opponent != null
}
}
loadSurprises(rollData, type) {
if (!rollData.type.passif) {
this.loadSurprise(rollData.active, this.getForceRequiseActiveActor(rollData, type))
this.loadSurprise(rollData.opponent, 0)
}
}
loadSurprise(who, forceRequise) {
if (who?.actor) {
foundry.utils.mergeObject(who,
StatusEffects.getActorEffetSurprise(who.actor, forceRequise),
{ overwrite: true, inPlace: true })
}
}
getForceRequiseActiveActor(rollData, type) {
switch (type) {
case ROLL_TYPE_ATTAQUE: return rollData.current[PART_ATTAQUE].attaque.forceRequise
case ROLL_TYPE_DEFENSE: return rollData.current[PART_DEFENSE].forceRequise
default: return 0
} }
} }
initFrom(rollData) { initFrom(rollData) {
return { return {
selected: {}, selected: {},
type: rollData.type, mode: {
current: rollData.mode.current
},
ids: { ids: {
sceneId: rollData.ids.sceneId, sceneId: rollData.ids.sceneId,
actorId: rollData.active.id, actorId: rollData.active.id,
actorTokenId: rollData.active.tokenId, actorTokenId: rollData.active.tokenId,
opponentId: rollData.type.opposed ? rollData.opponent.id : undefined, opponentId: rollData.mode.opposed ? rollData.opponent.id : undefined,
opponentTokenId: rollData.type.opposed ? rollData.opponent.tokenId : undefined, opponentTokenId: rollData.mode.opposed ? rollData.opponent.tokenId : undefined,
} }
} }
} }

View File

@@ -1,14 +1,14 @@
export const ROLL_TYPE_ATTAQUE = 'attaque' export const ROLL_MODE_ATTAQUE = 'attaque'
export const ROLL_TYPE_COMP = 'comp' export const ROLL_MODE_COMP = 'comp'
export const ROLL_TYPE_DEFENSE = 'defense' export const ROLL_MODE_DEFENSE = 'defense'
export const ROLL_TYPE_JEU = 'jeu' export const ROLL_MODE_JEU = 'jeu'
export const ROLL_TYPE_MEDITATION = 'meditation' export const ROLL_MODE_MEDITATION = 'meditation'
export const ROLL_TYPE_OEUVRE = 'oeuvre' export const ROLL_MODE_OEUVRE = 'oeuvre'
export const ROLL_TYPE_SORT = 'sort' export const ROLL_MODE_SORT = 'sort'
export const ROLL_TYPE_TACHE = 'tache' export const ROLL_MODE_TACHE = 'tache'
export const DIFF = { export const DIFF_MODE = {
LIBRE: 'libre', LIBRE: 'libre',
ATTAQUE: 'attaque', ATTAQUE: 'attaque',
IMPOSEE: 'imposee', IMPOSEE: 'imposee',
@@ -17,12 +17,12 @@ export const DIFF = {
AUCUN: 'aucun' AUCUN: 'aucun'
} }
export const DIFFS = { export const DIFF_MODES = {
[DIFF.LIBRE]: { key: DIFF.LIBRE, label: "Difficulté libre", libre: true, visible: true, max: 0 }, [DIFF_MODE.LIBRE]: { key: DIFF_MODE.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_MODE.ATTAQUE]: { key: DIFF_MODE.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_MODE.IMPOSEE]: { key: DIFF_MODE.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_MODE.DEFENSE]: { key: DIFF_MODE.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_MODE.DEFAUT]: { key: DIFF_MODE.DEFAUT, label: "Difficulté", libre: true, visible: true, max: 5 },
[DIFF.AUCUN]: { key: DIFF.AUCUN, label: "", libre: false, visible: false, max: 0 }, [DIFF_MODE.AUCUN]: { key: DIFF_MODE.AUCUN, label: "", libre: false, visible: false, max: 0 },
} }

View File

@@ -4,14 +4,12 @@ import { PART_COMP } from "./roll-part-comp.mjs";
import { RdDResolutionTable } from "../rdd-resolution-table.js"; import { RdDResolutionTable } from "../rdd-resolution-table.js";
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"; import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
import { PART_OEUVRE } from "./roll-part-oeuvre.mjs"; import { PART_OEUVRE } from "./roll-part-oeuvre.mjs";
import { RdDItemArme } from "../item/arme.js";
import { RdDBonus } from "../rdd-bonus.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RollDialogAdapter { export class RollDialogAdapter {
static async rollDice(rollData, rollTitle) { async rollDice(rollData, rollTitle) {
const chances = RollDialogAdapter.computeChances({ const chances = this.computeChances({
carac: rollData.current.carac.value, carac: rollData.current.carac.value,
diff: rollData.current.totaldiff, diff: rollData.current.totaldiff,
bonus: rollData.current.bonus, bonus: rollData.current.bonus,
@@ -20,13 +18,13 @@ export class RollDialogAdapter {
rollMode: rollData.current.rollmode.key rollMode: rollData.current.rollmode.key
}) })
const rolled = await RollDialogAdapter.rollChances(rollData, chances) const rolled = await this.rollChances(rollData, chances)
RollDialogAdapter.adjustRollDataForV1(rollData, rolled, rollTitle) this.adjustRollDataForV1(rollData, rolled, rollTitle)
return rolled return rolled
} }
static computeChances({ carac, diff, bonus, sign, showDice, rollMode }) { computeChances({ carac, diff, bonus, sign, showDice, rollMode }) {
const chances = foundry.utils.duplicate(RdDResolutionTable.computeChances(carac, diff)) const chances = foundry.utils.duplicate(RdDResolutionTable.computeChances(carac, diff))
RdDResolutionTable._updateChancesWithBonus(chances, bonus, diff) RdDResolutionTable._updateChancesWithBonus(chances, bonus, diff)
RdDResolutionTable._updateChancesFactor(chances, sign) RdDResolutionTable._updateChancesFactor(chances, sign)
@@ -35,10 +33,8 @@ export class RollDialogAdapter {
return chances return chances
} }
static async rollChances(rollData, chances) { async rollChances(rollData, chances) {
const rolled = await RdDResolutionTable.rollChances(chances, const rolled = await RdDResolutionTable.rollChances(chances, rollData.current.sign, rollData.current.resultat)
rollData.current.sign,
rollData.current.resultat)
rolled.caracValue = rollData.current.carac.value rolled.caracValue = rollData.current.carac.value
rolled.finalLevel = rollData.current.totaldiff rolled.finalLevel = rollData.current.totaldiff
rolled.bonus = rollData.current.bonus ?? 0 rolled.bonus = rollData.current.bonus ?? 0
@@ -46,7 +42,7 @@ export class RollDialogAdapter {
return rolled return rolled
} }
static adjustRollDataForV1(rollData, rolled, rollTitle) { adjustRollDataForV1(rollData, rolled, rollTitle) {
// temporaire pour être homogène roll v1 // temporaire pour être homogène roll v1
rollData.alias = rollData.active.actor.getAlias() rollData.alias = rollData.active.actor.getAlias()
// pour experience // pour experience
@@ -61,7 +57,7 @@ export class RollDialogAdapter {
const compKey = rollData.current.comp?.key const compKey = rollData.current.comp?.key
if (compKey) { if (compKey) {
rollData.competence = rollData.refs[PART_COMP].all.find(it => it.key == compKey)?.comp rollData.competence = rollData.refs[PART_COMP].all.find(it => it.key == compKey)?.comp
rollData.jetResistance = rollData.type.jetResistance rollData.jetResistance = rollData.mode.jetResistance
} }
const oeuvreKey = rollData.current.oeuvre?.key const oeuvreKey = rollData.current.oeuvre?.key
if (oeuvreKey) { if (oeuvreKey) {
@@ -91,29 +87,4 @@ export class RollDialogAdapter {
rollData.show.title = rollTitle rollData.show.title = rollTitle
} }
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,
attaque: {
// 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 { Misc } from "../misc.js";
import { RollTypeComp } from "./roll-type-comp.mjs"; import { RollModeComp } from "./roll-mode-comp.mjs";
import { RollTypeTache } from "./roll-type-tache.mjs"; import { RollModeTache } from "./roll-mode-tache.mjs";
import { RollTypeAttaque } from "./roll-type-attaque.mjs"; import { RollModeAttaque } from "./roll-mode-attaque.mjs";
import { RollTypeDefense } from "./roll-type-defense.mjs"; import { RollModeDefense } from "./roll-mode-defense.mjs";
import { RollTypeMeditation } from "./roll-type-meditation.mjs"; import { RollModeMeditation } from "./roll-mode-meditation.mjs";
import { RollTypeSort } from "./roll-type-sort.mjs"; import { RollModeSort } from "./roll-mode-sort.mjs";
import { RollTypeOeuvre } from "./roll-type-oeuvre.mjs"; import { RollModeOeuvre } from "./roll-mode-oeuvre.mjs";
import { RollTypeJeu } from "./roll-type-jeu.mjs"; import { RollModeJeu } from "./roll-mode-jeu.mjs";
import { RollPartAction } from "./roll-part-action.mjs"; import { RollPartAction } from "./roll-part-action.mjs";
import { RollPartActor } from "./roll-part-actor.mjs"; import { RollPartActor } from "./roll-part-actor.mjs";
import { RollPartAppelMoral } from "./roll-part-appelmoral.mjs"; import { RollPartAppelMoral } from "./roll-part-appelmoral.mjs";
import { RollPartAstrologique } from "./roll-part-astrologique.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 { RollPartCoeur } from "./roll-part-coeur.mjs";
import { PART_COMP, RollPartComp } from "./roll-part-comp.mjs"; import { PART_COMP, RollPartComp } from "./roll-part-comp.mjs";
import { RollPartConditions } from "./roll-part-conditions.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 { RollPartMoral } from "./roll-part-moral.mjs";
import { RollPartOpponent } from "./roll-part-opponent.mjs"; import { RollPartOpponent } from "./roll-part-opponent.mjs";
import { RollPartSurEnc } from "./roll-part-surenc.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 { RollPartTache } from "./roll-part-tache.mjs";
import { RollPartOeuvre } from "./roll-part-oeuvre.mjs"; import { RollPartOeuvre } from "./roll-part-oeuvre.mjs";
import { RollPartSort } from "./roll-part-sort.mjs"; import { RollPartSort } from "./roll-part-sort.mjs";
@@ -37,24 +37,23 @@ import { RollPartAttaque } from "./roll-part-attaque.mjs";
import { RollPartDefense } from "./roll-part-defense.mjs"; import { RollPartDefense } from "./roll-part-defense.mjs";
import { RollDialogAdapter } from "./roll-dialog-adapter.mjs"; import { RollDialogAdapter } from "./roll-dialog-adapter.mjs";
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"; import { ROLLDIALOG_SECTION } from "./roll-part.mjs";
import { ROLL_TYPE_COMP } from "./roll-constants.mjs"; import { ROLL_MODE_COMP } from "./roll-constants.mjs";
import ChatRollResult from "./chat-roll-result.mjs";
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api
const doNothing = (dialog) => { } const doNothing = (dialog) => { }
const ALL_ROLL_TYPES = [ const ROLL_MODE_TABS = [
new RollTypeComp(), new RollModeComp(),
new RollTypeTache(), new RollModeTache(),
new RollTypeAttaque(), new RollModeAttaque(),
new RollTypeDefense(), new RollModeDefense(),
new RollTypeSort(), // new RollModeParade??
new RollTypeMeditation(), // new RollModeEsquive??
new RollTypeOeuvre(), // new RollModeResistance ??
new RollTypeJeu(), new RollModeSort(),
// new RollTypeResistance ?? new RollModeMeditation(),
// new RollTypeFixedCarac ?? new RollModeOeuvre(),
new RollModeJeu(),
] ]
const BASIC_PARTS = new RollBasicParts() const BASIC_PARTS = new RollBasicParts()
@@ -96,7 +95,7 @@ const ROLL_PARTS = [
* @extends {Dialog} * @extends {Dialog}
* # Principes * # Principes
* - une seule fenêtre de dialogue (classe RollDialog) * - 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) * - gestion uniforme des modificateurs (classe RollPart)
* - un objet rollData contient les informations liées à un jet de dés * - 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 * - un rollData doit pouvoir être "réduit" pour fournir les informations significatives
@@ -107,15 +106,15 @@ const ROLL_PARTS = [
* - TODO: une classe de base RollChatMessage gerera les messages correspondant aux résultats du dés * - 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 ? * - 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. * 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. * attendues et ajoutées au rollData.
* - chaque type de fonctionnement peut définir le template de ChatMessage correspondant * - chaque mode de fonctionnement peut définir le template de ChatMessage correspondant
* - Le type de fonctionnement détermine aussi quelles sont les effets du jet: * - Le mode de fonctionnement détermine aussi quelles sont les effets du jet:
* - quelle ChatMessage afficher dans le tchat? * - quelle ChatMessage afficher dans le tchat?
* - en cas d'attaque/de défense, quelles sont les suites à donner? * - en cas d'attaque/de défense, quelles sont les suites à donner?
* - en cas de lancement de sort, réduire les points de rêve * - en cas de lancement de sort, réduire les points de rêve
@@ -177,16 +176,14 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
foundry.applications.handlebars.loadTemplates({ foundry.applications.handlebars.loadTemplates({
'roll-section': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-section.hbs', '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-table': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-table.hbs',
'roll-ajustements': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-ajustements.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-chances': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-chances.hbs',
'roll-button': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-button.hbs', 'roll-button': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-button.hbs',
}) })
ChatRollResult.onReady() foundry.applications.handlebars.loadTemplates(ROLL_MODE_TABS.map(m => m.template))
foundry.applications.handlebars.loadTemplates(ALL_ROLL_TYPES.map(m => m.template))
foundry.applications.handlebars.loadTemplates(ROLL_PARTS.map(p => p.template)) foundry.applications.handlebars.loadTemplates(ROLL_PARTS.map(p => p.template))
ROLL_PARTS.forEach(p => p.onReady()) ROLL_PARTS.forEach(p => p.onReady())
@@ -250,26 +247,43 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
// rien pour l'instant // rien pour l'instant
} }
constructor(rollData, rollOptions) {
super()
this.rollData = rollData
// const callbacks = this.rollOptions.callbacks.map(c =>
// r => r.activve.actor Promise.all(this.rollOptions.callbacks.map(async callback => await callback(rollData.active.actor, rollData)))
// )
this.rollOptions = {
callbacks: [
async (actor, r) => await actor.appliquerAjoutExperience(r),
async (actor, r) => await actor.appliquerAppelMoral(r),
...(rollOptions.callbacks ?? [])
],
customChatMessage: rollOptions.customChatMessage,
onRoll: rollOptions.onRoll ?? doNothing
}
this.$loadParts()
}
/** pre-configure les paramètres des différentes parties de la fenêtre (par exemple, prépare les listes de caractéristiques/compétences */ /** 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) { $loadParts() {
const rollData = this.rollData;
rollData.current = rollData.current ?? {} rollData.current = rollData.current ?? {}
rollData.selected = rollData.selected ?? {} rollData.selected = rollData.selected ?? {}
rollData.type = rollData.type ?? {} rollData.mode = rollData.mode ?? {}
rollData.type.retry = rollData.type.retry ?? false rollData.mode.retry = rollData.mode.retry ?? false
BASIC_PARTS.restore(rollData) BASIC_PARTS.restore(rollData)
const potential = ALL_ROLL_TYPES.find(m => m.code == rollData.type.current)?.code const loadedMode = ROLL_MODE_TABS.find(m => m.code == rollData.mode?.current)?.code
const allowed = rollData.type.retry && potential const allowedModes = ROLL_MODE_TABS.filter(m => m.isAllowed(rollData) && m.visible(rollData)).map(m => m.code)
? [potential]
: (rollData.type.allowed ?? ALL_ROLL_TYPES.filter(m => m.isAllowed(rollData) && m.visible(rollData)).map(m => m.code))
const rollType = allowed.find(c => c == rollData.type.current) ?? (allowed.length > 0 ? allowed[0].code : ROLL_TYPE_COMP);
rollData.type.allowed = allowed rollData.mode.allowed = rollData.mode.retry ? [loadedMode] : rollData.mode.allowed ?? ROLL_MODE_TABS.map(m => m.code)
rollData.type.current = rollType rollData.mode.current = allowedModes.find(m => m == rollData.mode?.current) ?? (allowedModes.length > 0 ? allowedModes[0] : ROLL_MODE_COMP)
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, {}]))); this.getSelectedMode().setRollDataMode(rollData)
rollData.options = rollData.options ?? { rollMode: game.settings.get("core", "rollMode") }
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.initialize(rollData))
ROLL_PARTS.forEach(p => p.restore(rollData)) ROLL_PARTS.forEach(p => p.restore(rollData))
@@ -278,62 +292,32 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
p.loadRefs(rollData) p.loadRefs(rollData)
p.prepareContext(rollData) p.prepareContext(rollData)
}) })
return rollData this.selectMode();
} }
static saveParts(rollData) { selectMode() {
const target = BASIC_PARTS.initFrom(rollData) this.rollData.mode.label = this.getSelectedMode().title(this.rollData)
ROLL_PARTS.filter(p => p.isActive(rollData)) this.getSelectedMode().setRollDataMode(this.rollData)
.forEach(p => p.storeClean(rollData, target)) this.getSelectedMode().onSelect(this.rollData);
target.attackerRoll = rollData.attackerRoll }
target.rolled = rollData.rolled
target.result = rollData.result $prepareRefs(rollData) {
target.done = target.done ?? {} 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 return target
} }
constructor(rollData, rollOptions) { getActiveParts() {
super() return ROLL_PARTS.filter(p => p.isActive(this.rollData))
this.rollData = RollDialog.$prepareRollData(rollData)
this.rollOptions = {
callbacks: [
async r => await r.active.actor.appliquerAjoutExperience(r),
async r => await r.active.actor.appliquerAppelMoral(r),
...(rollOptions.callbacks ?? [])
],
customChatMessage: rollOptions.customChatMessage,
onRollDone: rollOptions.onRollDone ?? doNothing
}
this.chatRollResult = new ChatRollResult();
this.selectType()
} }
selectType() { get title() {
const selectedType = this.getSelectedType(); return this.rollData.title ?? `Jet de dés de ${this.rollData.active.actor.name}`
this.rollData.type.label = selectedType.title(this.rollData)
selectedType.setRollDataType(this.rollData)
selectedType.onSelect(this.rollData)
ROLL_PARTS.find(it => it.code == PART_CARAC).filterCaracs(this.rollData)
ROLL_PARTS.find(it => it.code == PART_COMP).filterComps(this.rollData)
}
static getActiveParts(rollData) {
return ROLL_PARTS.filter(p => p.isActive(rollData))
}
// get title() {
// return this.rollData.title ?? `Jet de dés de ${this.rollData.active.actor.name}`
// }
rollTitle(rollData) {
return rollData.label ?? ROLL_PARTS
.filter(it => it.section == ROLLDIALOG_SECTION.ACTION)
.filter(it => it.isActive(rollData))
.map(it => it.title(rollData))
.reduce(Misc.joining(' '))
} }
async _onRender(context, options) { async _onRender(context, options) {
@@ -345,24 +329,24 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
this.roll() this.roll()
} }
) )
const buttonsType = this.element.querySelectorAll(`button[name="roll-type"]`) const buttonsMode = this.element.querySelectorAll(`button[name="roll-mode"]`)
buttonsType?.forEach(it => it.addEventListener( buttonsMode?.forEach(it => it.addEventListener(
"click", e => { "click", e => {
e.preventDefault() e.preventDefault()
this.rollData.type.current = e.currentTarget.dataset.type this.rollData.mode.current = e.currentTarget.dataset.mode
this.selectType() this.selectMode()
this.render() this.render()
} }
)) ))
Promise.all( 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) { getAjustements() {
return RollDialog.getActiveParts(rollData) return this.getActiveParts()
.map(p => p.getAjustements(rollData)) .map(p => p.getAjustements(this.rollData))
.reduce((a, b) => a.concat(b)) .reduce((a, b) => a.concat(b))
.sort((a, b) => a.diff == undefined ? 1 : b.diff == undefined ? -1 : 0) .sort((a, b) => a.diff == undefined ? 1 : b.diff == undefined ? -1 : 0)
} }
@@ -371,28 +355,28 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
return await foundry.applications.handlebars.renderTemplate('roll-table', { carac, diff }) return await foundry.applications.handlebars.renderTemplate('roll-table', { carac, diff })
} }
async _prepareContext() { async _prepareContext() {
const rollData = this.rollData const rollData = this.rollData
const types = ALL_ROLL_TYPES.filter(m => m.isAllowed(rollData) && m.visible(rollData)) const modes = ROLL_MODE_TABS.filter(m => m.isAllowed(rollData) && m.visible(rollData))
.map(m => m.toTypeData(rollData)) .map(m => m.toModeData(rollData))
BASIC_PARTS.loadSurprises(rollData, this.getSelectedType().code) this.setModeTitle()
rollData.type.label = this.getSelectedType()?.title(rollData)
//TOCHECK: set type.label ? const visibleRollParts = this.getActiveParts()
const visibleRollParts = RollDialog.getActiveParts(rollData) visibleRollParts.forEach(p => p.setExternalFilter(visibleRollParts, rollData))
visibleRollParts.forEach(p => p.applyExternalImpacts(visibleRollParts, rollData))
this.setSpecialComp(visibleRollParts); this.setSpecialComp(visibleRollParts);
visibleRollParts.forEach(p => p.prepareContext(rollData)) 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() const context = await super._prepareContext()
return foundry.utils.mergeObject( return foundry.utils.mergeObject(
{ {
types: types, modes: modes,
templates: templates, templates: templates,
rollData: rollData, rollData: rollData,
}, context) }, context)
@@ -402,46 +386,42 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
const specialComp = visibleRollParts.map(p => p.getSpecialComp(this.rollData)) const specialComp = visibleRollParts.map(p => p.getSpecialComp(this.rollData))
.reduce((a, b) => a.concat(b)) .reduce((a, b) => a.concat(b))
if (specialComp.length > 0) { if (specialComp.length > 0) {
const rollPartComp = RollDialog.getActiveParts(this.rollData) const rollPartComp = this.getActiveParts()
.find(it => it.code == PART_COMP); .find(it => it.code == PART_COMP);
rollPartComp?.setSpecialComp(this.rollData, specialComp) rollPartComp?.setSpecialComp(this.rollData, specialComp)
} }
} }
static calculAjustements(rollData) { calculAjustements() {
rollData.ajustements = RollDialog.getAjustements(rollData) this.rollData.ajustements = this.getAjustements()
rollData.ajustements.forEach(it => it.isDiff = it.diff != undefined) this.rollData.ajustements.forEach(it => it.isDiff = it.diff != undefined)
rollData.current.totaldiff = rollData.ajustements this.rollData.current.totaldiff = this.rollData.ajustements
.map(adj => adj.diff) .map(adj => adj.diff)
.filter(d => d != undefined) .filter(d => d != undefined)
.reduce(Misc.sum(), 0) .reduce(Misc.sum(), 0)
} }
getSelectedType() { setModeTitle() {
return ALL_ROLL_TYPES.find(m => m.code == this.rollData.type.current) this.rollData.mode.label = this.getSelectedMode()?.title(this.rollData)
}
getSelectedMode() {
return ROLL_MODE_TABS.find(m => m.code == this.rollData.mode.current)
} }
async roll() { async roll() {
// ROLL_PARTS.filter(p => p.isActive(this.rollData)) this.calculAjustements()
// .forEach(p => p.validate(this.rollData)) const rollData = this.rollData
console.info('Roll parts:', this.$saveParts())
const roll = RollDialog.saveParts(this.rollData) const rolled = await this.$rollDice(rollData)
RollDialog.loadRollData(roll) rollData.rolled = rolled
roll.current.resultat = this.rollData.current[PART_TRICHER]?.resultat ?? -1 Promise.all(this.rollOptions.callbacks.map(async callback => await callback(rollData.active.actor, rollData)))
roll.rolled = await this.$rollDice(roll) if (!this.rollOptions.customChatMessage) {
roll.result = this.getSelectedType(roll).getResult(roll) rollData.active.actor.$onRollCompetence(this.rollData)
console.info('RollDialog.roll:', roll) }
await Promise.all(this.rollOptions.callbacks.map(async callback => await callback(roll))) this.rollOptions.onRoll(this)
await this.chatRollResult.display(roll)
this.rollOptions.onRollDone(this)
} }
static loadRollData(roll) {
RollDialog.$prepareRollData(roll)
RollDialog.calculAjustements(roll)
roll.v2 = true
}
async defaultCallback(rollData, rolled) { async defaultCallback(rollData, rolled) {
await rollData.active.actor.appliquerAjoutExperience(rollData) await rollData.active.actor.appliquerAjoutExperience(rollData)
@@ -449,6 +429,15 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
} }
async $rollDice(rollData) { async $rollDice(rollData) {
return await RollDialogAdapter.rollDice(rollData, this.rollTitle(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

@@ -1,9 +1,9 @@
import { PART_JEU } from "./roll-part-jeu.mjs" import { PART_JEU } from "./roll-part-jeu.mjs"
import { RollType } from "./roll-type.mjs" import { RollMode } from "./roll-mode.mjs"
import { ROLL_TYPE_JEU } from "./roll-constants.mjs" import { ROLL_MODE_JEU } from "./roll-constants.mjs"
export class RollTypeJeu extends RollType { export class RollModeJeu extends RollMode {
get code() { return ROLL_TYPE_JEU } get code() { return ROLL_MODE_JEU }
get name() { return `Jouer` } get name() { return `Jouer` }
visible(rollData) { return rollData.active.actor.isPersonnage() } visible(rollData) { return rollData.active.actor.isPersonnage() }

View File

@@ -1,9 +1,9 @@
import { DIFF, ROLL_TYPE_MEDITATION } from "./roll-constants.mjs" import { DIFF_MODE, ROLL_MODE_MEDITATION } from "./roll-constants.mjs"
import { PART_MEDITATION } from "./roll-part-meditation.mjs" import { PART_MEDITATION } from "./roll-part-meditation.mjs"
import { RollType } from "./roll-type.mjs" import { RollMode } from "./roll-mode.mjs"
export class RollTypeMeditation extends RollType { export class RollModeMeditation extends RollMode {
get code() { return ROLL_TYPE_MEDITATION } get code() { return ROLL_MODE_MEDITATION }
get name() { return `Méditation draconique` } get name() { return `Méditation draconique` }
visible(rollData) { return rollData.active.actor.isHautRevant() } visible(rollData) { return rollData.active.actor.isHautRevant() }
@@ -14,6 +14,6 @@ export class RollTypeMeditation extends RollType {
} }
onSelect(rollData) { onSelect(rollData) {
this.setDiffType(rollData, DIFF.AUCUN) 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

@@ -1,9 +1,9 @@
import { DIFF, ROLL_TYPE_TACHE } from "./roll-constants.mjs" import { DIFF_MODE, ROLL_MODE_TACHE } from "./roll-constants.mjs"
import { PART_TACHE } from "./roll-part-tache.mjs" import { PART_TACHE } from "./roll-part-tache.mjs"
import { RollType } from "./roll-type.mjs" import { RollMode } from "./roll-mode.mjs"
export class RollTypeTache extends RollType { export class RollModeTache extends RollMode {
get code() { return ROLL_TYPE_TACHE } get code() { return ROLL_MODE_TACHE }
get name() { return `Travailler à une tâche` } get name() { return `Travailler à une tâche` }
visible(rollData) { return rollData.active.actor.isPersonnage() } visible(rollData) { return rollData.active.actor.isPersonnage() }
@@ -14,6 +14,6 @@ export class RollTypeTache extends RollType {
} }
onSelect(rollData) { onSelect(rollData) {
this.setDiffType(rollData, DIFF.AUCUN) 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 } get section() { return ROLLDIALOG_SECTION.ACTION }
title(rollData) { title(rollData) {
return rollData.type.label return rollData.mode.label
} }
prepareContext(rollData) { prepareContext(rollData) {
const current = this.getCurrent(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 } get useCheckboxTemplate() { return false }
visible(rollData) { visible(rollData) {
return this.$isUsingAstrologie() return this.$isUsingAstrologie() && (
&& (this.isJetChance(rollData) || this.isLancementRituel(rollData)) this.isJetChance(rollData)
|| this.isLancementRituel(rollData)
)
} }
isLancementRituel(rollData) { isLancementRituel(rollData) {

View File

@@ -1,21 +1,26 @@
import { Grammar } from "../grammar.js"
import { RdDBonus } from "../rdd-bonus.js" import { RdDBonus } from "../rdd-bonus.js"
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js" import { StatusEffects } from "../settings/status-effects.js"
import { ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs" import { ROLL_MODE_ATTAQUE } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs" import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP } from "./roll-part-comp.mjs" import { PART_COMP } from "./roll-part-comp.mjs"
import { RollPartSelect } from "./roll-part-select.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' 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 { export class RollPartAttaque extends RollPartSelect {
get code() { return PART_ATTAQUE } get code() { return PART_ATTAQUE }
get section() { return ROLLDIALOG_SECTION.CHOIX } 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) { loadRefs(rollData) {
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
@@ -27,47 +32,51 @@ export class RollPartAttaque extends RollPartSelect {
} }
} }
store(rollData, targetData) {
super.store(rollData, targetData)
this.getSaved(targetData).dmg = this.getCurrent(rollData).dmg
}
restore(rollData) {
super.restore(rollData)
this.getCurrent(rollData).dmg = this.getSaved(rollData).dmg
}
choices(refs) { return refs.attaques } choices(refs) { return refs.attaques }
static $extractAttaque(attaque, actor) { static $extractAttaque(action, actor) {
return { return {
key: `${attaque.action}::${attaque.name}`, key: `${action.action}::${action.name}`,
label: attaque.name, label: action.name,
attaque: attaque, action: action,
tactique: TACTIQUES[0], tactique: "",
arme: action.arme,
comp: action.comp,
} }
} }
prepareContext(rollData) { prepareContext(rollData) {
const current = this.getCurrent(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) { dmgRollV2(rollData, current) {
const current = this.getCurrent(rollData) const actor = rollData.active.actor
const ajustements = [] const defender = rollData.opponent.actor
if (current.tactique) { const dmgArme = RdDBonus.dmgArme(current.arme, current.action.dommagesArme)
ajustements.push({ label: current.tactique.label, diff: current.tactique.attaque }) 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) { dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere
ajustements.push({ label: rollData.opponent.surprise.label, diff: rollData.opponent.surprise.attaque }) return dmg;
} }
return ajustements
}
$selectAttaque(rollData, key) { $selectAttaque(rollData, key) {
this.selectByKey(rollData, key) this.selectByKey(rollData, key, 0)
} }
async _onRender(rollDialog, context, options) { async _onRender(rollDialog, context, options) {
@@ -80,13 +89,14 @@ export class RollPartAttaque extends RollPartSelect {
const selectOptions = e.currentTarget.options const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex const index = selectOptions.selectedIndex
this.$selectAttaque(rollDialog.rollData, selectOptions[index]?.value) this.$selectAttaque(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.setModeTitle()
rollDialog.render() rollDialog.render()
}) })
selectTactique.addEventListener("change", e => { selectTactique.addEventListener("change", e => {
const selectOptions = e.currentTarget.options const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex const index = selectOptions.selectedIndex
current.tactique = RdDBonus.find(selectOptions[index]?.value) current.tactique = TACTIQUES[index].key
rollDialog.render() rollDialog.render()
}) })
@@ -96,14 +106,16 @@ export class RollPartAttaque extends RollPartSelect {
}) })
} }
impactOtherPart(part, rollData) { getExternalPartsFilter(partCode, rollData) {
if (this.visible(rollData)) { if (this.visible(rollData)) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
switch (part.code) { switch (partCode) {
case PART_CARAC: return part.filterCaracs(rollData, [current.attaque.carac.key]) case PART_CARAC: return p => Grammar.equalsInsensitive(current.action.carac.key, p.key)
case PART_COMP: return part.filterComps(rollData, [current.attaque.comp?.name]) case PART_COMP: return p => p.label == current.comp?.name
} }
} }
return undefined return undefined
} }
} }

View File

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

View File

@@ -45,14 +45,9 @@ export class RollPartComp extends RollPartSelect {
} }
} }
filterComps(rollData, allowed = []) { setFilter(rollData, filter) {
allowed = allowed.filter(it => it != undefined)
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
refs.comps = allowed.length > 0 refs.comps = refs.all.filter(filter)
// ? refs.all.filter(it => allowed.includes(Grammar.toLowerCaseNoAccent(it.label)))
? refs.all.filter(it => allowed.includes(it.label))
: refs.all
this.$selectComp(rollData)
} }
prepareContext(rollData) { prepareContext(rollData) {

View File

@@ -1,5 +1,4 @@
import { SYSTEM_RDD } from "../constants.js"; import { SYSTEM_RDD } from "../constants.js";
import { Misc } from "../misc.js";
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"; import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs";
const CONDITIONS = "conditions" const CONDITIONS = "conditions"
@@ -51,7 +50,7 @@ export class RollPartConditions extends RollPart {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
current.min = game.settings.get(SYSTEM_RDD, this.settingMin()) current.min = game.settings.get(SYSTEM_RDD, this.settingMin())
current.max = game.settings.get(SYSTEM_RDD, this.settingMax()) current.max = game.settings.get(SYSTEM_RDD, this.settingMax())
current.value = Misc.inRange(current.value ?? 0, current.min, current.max) current.value = current.value ?? 0
} }
getAjustements(rollData) { getAjustements(rollData) {
@@ -65,12 +64,11 @@ export class RollPartConditions extends RollPart {
async _onRender(rollDialog, context, options) { async _onRender(rollDialog, context, options) {
const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`) const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)
input?.addEventListener("input", e => this.onInputChange(e, rollDialog)) input?.addEventListener("change", e => {
} const current = this.getCurrent(rollDialog.rollData)
current.value = parseInt(e.currentTarget.value)
onInputChange(event, rollDialog) {
this.getCurrent(rollDialog.rollData).value = parseInt(event.currentTarget.value)
rollDialog.render() rollDialog.render()
})
} }
} }

View File

@@ -1,133 +1,21 @@
import { ITEM_TYPES } from "../constants.js" import { ROLL_MODE_DEFENSE } from "./roll-constants.mjs"
import { Grammar } from "../grammar.js" import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
import { ATTAQUE_TYPE, RdDItemArme } from "../item/arme.js"
import { RdDBonus } from "../rdd-bonus.js"
import { CARACS } from "../rdd-carac.js"
import { StatusEffects } from "../settings/status-effects.js"
import { DIFF, ROLL_TYPE_DEFENSE } 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 { PART_SIGN } from "./roll-part-sign.mjs"
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
export const PART_DEFENSE = 'defense' export const PART_DEFENSE = 'defense'
export class RollPartDefense extends RollPartSelect { export class RollPartDefense extends RollPart {
get code() { return PART_DEFENSE } get code() { return PART_DEFENSE }
get section() { return ROLLDIALOG_SECTION.CHOIX } get section() { return ROLLDIALOG_SECTION.CHOIX }
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_DEFENSE) } visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_DEFENSE) }
static getDiffAttaque(attackerRoll) {
// TODO: rollDataV2?
return attackerRoll.diffLibre;
}
loadRefs(rollData) { loadRefs(rollData) {
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
const attackerRoll = rollData.attackerRoll refs.defenses =[]
const defenseur = rollData.active.actor
refs.isDistance = [ATTAQUE_TYPE.TIR, ATTAQUE_TYPE.LANCER].find(it => it == attackerRoll?.main)
const esquives = refs.isDistance == ATTAQUE_TYPE.TIR ? [] : defenseur.getCompetencesEsquive()
.map(it => RollPartDefense.$extractEsquive(it, defenseur))
const parades = defenseur.items.filter(it => it.isParade() && (!refs.isDistance || it.isBouclier()))
.map(it => RollPartDefense.$extractParade(it, attackerRoll?.attaque.arme, defenseur))
refs.defenses = [...esquives, ...parades].filter(it => it != undefined)
this.$selectDefense(rollData)
} }
static $extractEsquive(esquive, defenseur) { isForceInsuffisante(rollData) {
return { return true
key: esquive.id,
label: esquive.name,
img: esquive.img,
// TODO: carac pour créatures
carac: defenseur.isPersonnage() ? CARACS.DEROBEE : esquive.name,
verb: "esquive",
comp: esquive,
isEsquive: true
}
} }
static $extractParade(armeDefense, armeAttaque, defenseur) {
const comp = (ITEM_TYPES.competencecreature == armeDefense.type)
? armeDefense
: defenseur.getCompetence(armeDefense.system.competence)
return {
key: armeDefense.id,
label: 'Parade ' + armeDefense.name,
img: armeDefense.img,
// TODO: carac pour créatures
carac: defenseur.isPersonnage() ? CARACS.MELEE : comp.name,
verb: "pare",
comp: comp,
arme: armeDefense,
forceRequise: armeDefense ? RdDItemArme.valeurMain(armeDefense.system.force ?? 0, RdDItemArme.getMainAttaque(comp)) : 0,
typeParade: armeAttaque ? RdDItemArme.defenseArmeParade(armeDefense, armeAttaque) : 'norm',
isEsquive: false
}
}
prepareContext(rollData) {
// current.dmg = this.$dmgRollV2(rollData, current)
}
getAjustements(rollData) {
return []
}
choices(refs) { return refs.defenses }
$selectDefense(rollData, key) {
this.selectByKey(rollData, key)
}
async _onRender(rollDialog, context, options) {
const selectDefense = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-defense"]`)
selectDefense.addEventListener("change", e => {
const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex
this.$selectDefense(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.render()
})
}
impactOtherPart(part, rollData) {
if (this.visible(rollData)) {
const current = this.getCurrent(rollData)
switch (part.code) {
case PART_CARAC: return part.filterCaracs(rollData, [current.carac])
case PART_COMP: return part.filterComps(rollData, [current.comp?.name])
case PART_DIFF: return part.setDiff(rollData, this.getDiffDefense(rollData))
case PART_SIGN: return part.setArmeDisparate(rollData, this.isArmeDisparate(rollData))
}
}
return undefined
}
isArmeDisparate(rollData) {
const armeDefense = this.getCurrent(rollData).arme
if (armeDefense) {
const armeAttaque = rollData.attackerRoll?.attaque.arme
return RdDItemArme.defenseArmeParade(armeAttaque, armeDefense) == 'sign'
}
return false
}
getDiffDefense(rollData) {
const current = this.getCurrent(rollData)
const refs = this.getRefs(rollData)
if (refs.isDistance || !rollData.attackerRoll) {
// Déterminer la difficulté de parade
return { diff: 0, type: DIFF.LIBRE }
}
else {
return { diff: rollData.attackerRoll.diff ?? 0, type: DIFF.DEFENSE }
}
}
} }

View File

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

View File

@@ -1,7 +1,7 @@
import { Grammar } from "../grammar.js" import { Grammar } from "../grammar.js"
import { ITEM_TYPES } from "../constants.js" import { ITEM_TYPES } from "../constants.js"
import { CARACS } from "../rdd-carac.js" import { CARACS } from "../rdd-carac.js"
import { ROLL_TYPE_JEU } from "./roll-constants.mjs" import { ROLL_MODE_JEU } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs" import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP } from "./roll-part-comp.mjs" import { PART_COMP } from "./roll-part-comp.mjs"
import { RollPartSelect } from "./roll-part-select.mjs" import { RollPartSelect } from "./roll-part-select.mjs"
@@ -17,7 +17,7 @@ export class RollPartJeu extends RollPartSelect {
get section() { return ROLLDIALOG_SECTION.CHOIX } get section() { return ROLLDIALOG_SECTION.CHOIX }
isValid(rollData) { return rollData.active.actor.isPersonnage() } isValid(rollData) { return rollData.active.actor.isPersonnage() }
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_JEU) } visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_JEU) }
loadRefs(rollData) { loadRefs(rollData) {
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
@@ -68,8 +68,8 @@ export class RollPartJeu extends RollPartSelect {
prepareContext(rollData) { prepareContext(rollData) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
if (rollData.type.current == ROLL_TYPE_JEU && current) { if (rollData.mode.current == ROLL_MODE_JEU && current) {
rollData.type.opposed = true rollData.mode.opposed = true
} }
} }
@@ -86,16 +86,17 @@ export class RollPartJeu extends RollPartSelect {
const selectOptions = e.currentTarget.options const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex const index = selectOptions.selectedIndex
this.$selectJeu(rollDialog.rollData, selectOptions[index]?.value) this.$selectJeu(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.setModeTitle()
rollDialog.render() rollDialog.render()
}) })
} }
impactOtherPart(part, rollData) { getExternalPartsFilter(partCode, rollData) {
if (this.visible(rollData)) { if (this.visible(rollData)) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
switch (part.code) { switch (partCode) {
case PART_CARAC: return part.filterCaracs(rollData, current.caracs) case PART_CARAC: return p => current.caracs?.includes(Grammar.toLowerCaseNoAccent(p.key))
case PART_COMP: return part.filterComps(rollData,[current.comp?.name]) case PART_COMP: return p => p.label == current.comp?.name
} }
} }
return undefined return undefined

View File

@@ -1,9 +1,9 @@
import { ITEM_TYPES } from "../constants.js" import { ITEM_TYPES } from "../constants.js"
import { Grammar } from "../grammar.js" import { Grammar } from "../grammar.js"
import { CARACS, RdDCarac } from "../rdd-carac.js" import { RdDCarac } from "../rdd-carac.js"
import { RdDTimestamp } from "../time/rdd-timestamp.js" import { RdDTimestamp } from "../time/rdd-timestamp.js"
import { TMRUtility } from "../tmr-utility.js" import { TMRUtility } from "../tmr-utility.js"
import { ROLL_TYPE_MEDITATION } from "./roll-constants.mjs" import { ROLL_MODE_MEDITATION } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs" import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP } from "./roll-part-comp.mjs" import { PART_COMP } from "./roll-part-comp.mjs"
import { RollPartSelect } from "./roll-part-select.mjs" import { RollPartSelect } from "./roll-part-select.mjs"
@@ -17,7 +17,7 @@ export class RollPartMeditation extends RollPartSelect {
get section() { return ROLLDIALOG_SECTION.CHOIX } get section() { return ROLLDIALOG_SECTION.CHOIX }
isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() } isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() }
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_MEDITATION) } visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_MEDITATION) }
loadRefs(rollData) { loadRefs(rollData) {
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
@@ -86,6 +86,7 @@ export class RollPartMeditation extends RollPartSelect {
const index = selectOptions.selectedIndex const index = selectOptions.selectedIndex
this.$selectMeditation(rollDialog.rollData, selectOptions[index]?.value) this.$selectMeditation(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.render() rollDialog.render()
rollDialog.setModeTitle()
}) })
this.setupListenerCondition(rollDialog, 'isComportement') this.setupListenerCondition(rollDialog, 'isComportement')
@@ -103,12 +104,12 @@ export class RollPartMeditation extends RollPartSelect {
}) })
} }
impactOtherPart(part, rollData) { getExternalPartsFilter(partCode, rollData) {
if (this.visible(rollData)) { if (this.visible(rollData)) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
switch (part.code) { switch (partCode) {
case PART_CARAC: return part.filterCaracs(rollData, [CARACS.INTELLECT]) case PART_CARAC: return p => RdDCarac.isIntellect(p.key)
case PART_COMP: return part.filterComps(rollData,[current.comp?.name]) case PART_COMP: return p => p.label == current.comp?.name
} }
} }
return undefined return undefined

View File

@@ -1,7 +1,8 @@
import { ITEM_TYPES } from "../constants.js" import { ITEM_TYPES } from "../constants.js"
import { Grammar } from "../grammar.js"
import { Misc } from "../misc.js" import { Misc } from "../misc.js"
import { CARACS } from "../rdd-carac.js" import { CARACS } from "../rdd-carac.js"
import { ROLL_TYPE_OEUVRE } from "./roll-constants.mjs" import { ROLL_MODE_OEUVRE } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs" import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP } from "./roll-part-comp.mjs" import { PART_COMP } from "./roll-part-comp.mjs"
import { RollPartSelect } from "./roll-part-select.mjs" import { RollPartSelect } from "./roll-part-select.mjs"
@@ -37,7 +38,7 @@ export class RollPartOeuvre extends RollPartSelect {
get section() { return ROLLDIALOG_SECTION.CHOIX } get section() { return ROLLDIALOG_SECTION.CHOIX }
isValid(rollData) { return rollData.active.actor.isPersonnage() } isValid(rollData) { return rollData.active.actor.isPersonnage() }
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_OEUVRE) } visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_OEUVRE) }
loadRefs(rollData) { loadRefs(rollData) {
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
@@ -58,7 +59,6 @@ export class RollPartOeuvre extends RollPartSelect {
label: oeuvre.name, label: oeuvre.name,
art: art, art: art,
caracs: art.caracs(oeuvre), caracs: art.caracs(oeuvre),
qualite: oeuvre.system.niveau,
value: -oeuvre.system.niveau, value: -oeuvre.system.niveau,
oeuvre: oeuvre, oeuvre: oeuvre,
comp: actor.getCompetence(art.competence(oeuvre)) comp: actor.getCompetence(art.competence(oeuvre))
@@ -80,16 +80,17 @@ export class RollPartOeuvre extends RollPartSelect {
const selectOptions = e.currentTarget.options const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex const index = selectOptions.selectedIndex
this.$selectOeuvre(rollDialog.rollData, selectOptions[index]?.value) this.$selectOeuvre(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.setModeTitle()
rollDialog.render() rollDialog.render()
}) })
} }
impactOtherPart(part, rollData) { getExternalPartsFilter(partCode, rollData) {
if (this.visible(rollData)) { if (this.visible(rollData)) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
switch (part.code) { switch (partCode) {
case PART_CARAC: return part.filterCaracs(rollData, current.caracs) case PART_CARAC: return p => current.caracs?.includes(Grammar.toLowerCaseNoAccent(p.key))
case PART_COMP: return part.filterComps(rollData,[current.comp?.name]) case PART_COMP: return p => p.label == current.comp?.name
} }
} }
return undefined return undefined

View File

@@ -7,6 +7,6 @@ export class RollPartOpponent extends RollPart {
get code() { return OPPONENT } get code() { return OPPONENT }
get section() { return ROLLDIALOG_SECTION.ACTION } get section() { return ROLLDIALOG_SECTION.ACTION }
visible(rollData) { return rollData.type.opposed } visible(rollData) { return rollData.mode.opposed }
title(rollData) { return rollData.opponent?.name ?? '' } title(rollData) { return rollData.opponent?.name ?? '' }
} }

View File

@@ -1,7 +1,7 @@
import { Misc } from "../misc.js" import { Misc } from "../misc.js"
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"
import { StatusEffects } from "../settings/status-effects.js" import { StatusEffects } from "../settings/status-effects.js"
import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs" import { ROLL_MODE_ATTAQUE, ROLL_MODE_DEFENSE } from "./roll-constants.mjs"
import { PART_ATTAQUE, RollPartAttaque } from "./roll-part-attaque.mjs"
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
export const PART_SIGN = "sign" export const PART_SIGN = "sign"
@@ -23,8 +23,13 @@ export class RollPartSign extends RollPart {
this.setSaved(targetData, this.getCurrent(rollData)) this.setSaved(targetData, this.getCurrent(rollData))
} }
// visible(rollData) {
// const current = this.getCurrent(rollData)
// return current.surprise != ''
// }
isCombat(rollData) { isCombat(rollData) {
return [ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE].includes(rollData.type.current) || rollData.type.isCombat return [ROLL_MODE_ATTAQUE, ROLL_MODE_DEFENSE].includes(rollData.mode.current) || rollData.mode.isCombat
} }
prepareContext(rollData) { prepareContext(rollData) {
@@ -32,53 +37,56 @@ export class RollPartSign extends RollPart {
} }
setFromState(rollData) { setFromState(rollData) {
if (rollData.type.retry) { if (rollData.mode.retry) {
return return
} }
const actor = rollData.active.actor; const actor = rollData.active.actor;
const isCombat = this.isCombat(rollData) const isCombat = this.isCombat(rollData)
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
current.armeDisparate = isCombat && current.armeDisparate current.surprise = actor.getSurprise(isCombat)
current.surprise = actor.getSurprise(isCombat) // TODO: could be from rollData.active.surprise??
current.reasons = actor.getEffects(it => StatusEffects.niveauSurprise(it) > 0).map(it => it.name) current.reasons = actor.getEffects(it => StatusEffects.niveauSurprise(it) > 0).map(it => it.name)
current.diviseur = 1 current.diviseur = 1
if (current.surprise == 'demi') {
current.diviseur *= 2
}
if (isCombat && actor.isDemiReve()) { if (isCombat && actor.isDemiReve()) {
current.reasons.push('Demi-rêve en combat') current.reasons.push('Demi-rêve en combat')
} }
if (this.isParadeArmeDisparate(current)) { if (current.surprise == 'demi') {
current.diviseur *= 2 current.diviseur *= 2
current.reasons.push('Armes disparates')
} }
if (this.isAttaqueFinesse(rollData)) { if (this.isAttaqueFinesse(rollData)) {
current.diviseur *= 2 current.diviseur *= 2
current.reasons.push('Particulière en finesse') current.reasons.push('Attaque en finesse')
} }
if (this.isForceInsuffisante(rollData)) {
if (!ReglesOptionnelles.isUsing('tripleSignificative')) { current.diviseur *= 2
current.diviseur = Math.min(current.diviseur, 4); current.reasons.push('Force insuffisante')
} }
current.reason = current.reasons.join(', ') current.reason = current.reasons.join(', ')
} }
isAttaqueFinesse(rollData) { isForceInsuffisante(rollData) {
return ROLL_TYPE_DEFENSE == rollData.type.current && rollData.attaque?.particuliere == 'finesse' if ([ROLL_MODE_ATTAQUE, ROLL_MODE_DEFENSE].includes(rollData.mode.current)) {
const arme = rollData.current[rollData.mode.current]?.arme
const actor = rollData.active.actor
if (actor?.isPersonnage() && arme) {
const requise = parseInt(arme?.system.force ?? 0)
const force = parseInt(actor.system.carac.force.value)
return requise > force
}
}
return false
} }
isParadeArmeDisparate(current) { isAttaqueFinesse(rollData) {
return current.armeDisparate // this.rollData.selected[PART_DEFENSE] && attaquant avec particulière en finesse
return ROLL_MODE_DEFENSE == rollData.mode.current && true
} }
getAjustements(rollData) { getAjustements(rollData) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
if (current.surprise == 'demi') { if (current.surprise == 'demi') {
return [ return [{ label: 'Significative requise ' + Misc.getFractionOneN(current.diviseur), diff: undefined }]
{ label: 'Significative requise ' + Misc.getFractionOneN(current.diviseur), diff: undefined },
...current.reasons.map(it => { return { label: '<i class="fa-solid fa-triangle-exclamation"></i> ' + it, diff: undefined } })
]
} }
return [] return []
} }
@@ -92,7 +100,4 @@ export class RollPartSign extends RollPart {
}) })
} }
setArmeDisparate(rollData, armeDisparate) {
this.getCurrent(rollData).armeDisparate = armeDisparate
}
} }

View File

@@ -1,12 +1,11 @@
import { ITEM_TYPES } from "../constants.js" import { ITEM_TYPES } from "../constants.js"
import { ROLL_TYPE_SORT } from "./roll-constants.mjs" import { ROLL_MODE_SORT } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs" import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP } from "./roll-part-comp.mjs" import { PART_COMP } from "./roll-part-comp.mjs"
import { ROLLDIALOG_SECTION } from "./roll-part.mjs" import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
import { TMRUtility } from "../tmr-utility.js" import { TMRUtility } from "../tmr-utility.js"
import { RdDItemSort } from "../item-sort.js" import { RdDItemSort } from "../item-sort.js"
import { RollPartSelect } from "./roll-part-select.mjs" import { RollPartSelect } from "./roll-part-select.mjs"
import { CARACS } from "../rdd-carac.js"
export const PART_SORT = "sort" export const PART_SORT = "sort"
@@ -18,7 +17,7 @@ export class RollPartSort extends RollPartSelect {
get section() { return ROLLDIALOG_SECTION.CHOIX } get section() { return ROLLDIALOG_SECTION.CHOIX }
isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() } isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() }
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_SORT) } visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_SORT) }
loadRefs(rollData) { loadRefs(rollData) {
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
@@ -98,6 +97,7 @@ export class RollPartSort extends RollPartSelect {
const selectOptions = e.currentTarget.options const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex const index = selectOptions.selectedIndex
this.$selectSort(rollDialog.rollData, selectOptions[index]?.value) this.$selectSort(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.setModeTitle()
rollDialog.render() rollDialog.render()
}) })
@@ -115,12 +115,12 @@ export class RollPartSort extends RollPartSelect {
}) })
} }
impactOtherPart(part, rollData) { getExternalPartsFilter(partCode, rollData) {
if (this.visible(rollData)) { if (this.visible(rollData)) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
switch (part.code) { switch (partCode) {
case PART_CARAC: return part.filterCaracs(rollData, [CARACS.REVE]) case PART_CARAC: return p => p.key == 'reve'
case PART_COMP: return part.filterComps(rollData,current.draconics ?? []) case PART_COMP: return p => current.draconics?.includes(p.label)
} }
} }
return undefined return undefined

View File

@@ -1,6 +1,6 @@
import { ITEM_TYPES } from "../constants.js" import { ITEM_TYPES } from "../constants.js"
import { Grammar } from "../grammar.js" import { Grammar } from "../grammar.js"
import { ROLL_TYPE_TACHE } from "./roll-constants.mjs" import { ROLL_MODE_TACHE } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs" import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP } from "./roll-part-comp.mjs" import { PART_COMP } from "./roll-part-comp.mjs"
import { RollPartSelect } from "./roll-part-select.mjs" import { RollPartSelect } from "./roll-part-select.mjs"
@@ -14,7 +14,7 @@ export class RollPartTache extends RollPartSelect {
get section() { return ROLLDIALOG_SECTION.CHOIX } get section() { return ROLLDIALOG_SECTION.CHOIX }
isValid(rollData) { return rollData.active.actor.isPersonnage() } isValid(rollData) { return rollData.active.actor.isPersonnage() }
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_TACHE) } visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_TACHE) }
loadRefs(rollData) { loadRefs(rollData) {
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
@@ -48,16 +48,17 @@ export class RollPartTache extends RollPartSelect {
const selectOptions = e.currentTarget.options const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex const index = selectOptions.selectedIndex
this.$selectTache(rollDialog.rollData, selectOptions[index]?.value) this.$selectTache(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.setModeTitle()
rollDialog.render() rollDialog.render()
}) })
} }
impactOtherPart(part, rollData) { getExternalPartsFilter(partCode, rollData) {
if (this.visible(rollData)) { if (this.visible(rollData)) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
switch (part.code) { switch (partCode) {
case PART_CARAC: return part.filterCaracs(rollData, [current?.tache.system.carac]) case PART_CARAC: return p => Grammar.equalsInsensitive(p.key, current?.tache.system.carac)
case PART_COMP: return part.filterComps(rollData, [current.comp?.name]) case PART_COMP: return p => p.label == current?.comp.name
} }
} }
return undefined return undefined

View File

@@ -1,7 +1,6 @@
import { Misc } from "../misc.js"
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
export const PART_TRICHER = "tricher" const PART_TRICHER = "tricher"
export class RollPartTricher extends RollPart { export class RollPartTricher extends RollPart {
@@ -12,20 +11,21 @@ export class RollPartTricher extends RollPart {
prepareContext(rollData) { prepareContext(rollData) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
current.resultat = Misc.inRange(current.resultat == undefined ? -1 : current.resultat, -1, 100) if (current.resultat == undefined) {
current.resultat = -1
}
} }
getAjustements(rollData) { getAjustements(rollData) {
rollData.current.resultat = this.getCurrent(rollData).resultat
return [] return []
} }
async _onRender(rollDialog, context, options) { async _onRender(rollDialog, context, options) {
const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`) const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)
input?.addEventListener("input", e => this.onInputChange(e, rollDialog)) input?.addEventListener("change", e => {
} this.getCurrent(rollDialog.rollData).resultat = parseInt(e.currentTarget.value)
})
onInputChange(event, rollDialog) {
this.getCurrent(rollDialog.rollData).resultat = parseInt(event.currentTarget.value)
} }
} }

View File

@@ -1,3 +1,5 @@
import { Misc } from "../misc.js"
export const ROLLDIALOG_SECTION = { export const ROLLDIALOG_SECTION = {
ACTION: 'action', ACTION: 'action',
CARAC: 'carac', CARAC: 'carac',
@@ -51,30 +53,14 @@ export class RollPart {
} }
restore(rollData) { } restore(rollData) { }
store(rollData, targetData) { }
storeClean(rollData, targetData) {
this.store(rollData, targetData)
if (rollData.selected[this.code]) {
const toDelete = Object.entries(rollData.selected[this.code])
.map(([k, v]) => v == undefined ? k : undefined)
.filter(k => k != undefined)
toDelete.forEach(k => delete rollData.selected[this.code][k])
if (Object.keys(rollData.selected[this.code]).length == 0) {
delete rollData.selected[this.code]
}
}
}
store(rollData, targetData) {
this.setSaved(targetData, { key: this.getCurrent(rollData).key })
}
/** /**
* le texte à ajouter dans la barre de titre * le texte à ajouter dans la barre de titre
* @returns une chaîne vide si rien ne doit être affiché * @returns une chaîne vide si rien ne doit être affiché
*/ */
title() { return '' } title() { return '' }
isRollType(rollData, type) { return rollData.type.current == type } isRollMode(rollData, mode) { return rollData.mode.current == mode }
isActive(rollData) { return this.isValid(rollData) && this.visible(rollData) } isActive(rollData) { return this.isValid(rollData) && this.visible(rollData) }
isValid(rollData) { return true } isValid(rollData) { return true }
@@ -85,18 +71,17 @@ export class RollPart {
prepareContext(rollData) { } prepareContext(rollData) { }
/** permet de sauvegarder dans rollData les informations (cas des champs edit) */
validate(rollData) {}
/** ---- cross roll-part filtering ---- */ /** ---- cross roll-part filtering ---- */
applyImpact(rollData, filter) { } setFilter(rollData, filter) { }
getSpecialComp(rollData) { return [] } getSpecialComp(rollData) { return [] }
setSpecialComp(comps) { } setSpecialComp(comps) { }
impactOtherPart(partCode, rollData) { } getExternalPartsFilter(partCode, rollData) { return undefined }
setExternalFilter(visibleRollParts, rollData) {
applyExternalImpacts(rollParts, rollData) { const predicate = Misc.and(
rollParts.forEach(part => part.impactOtherPart(this, rollData)) visibleRollParts.map(p => p.getExternalPartsFilter(this.code, rollData)).filter(f => f != undefined)
)
this.setFilter(rollData, predicate);
} }
toTemplateData() { toTemplateData() {

View File

@@ -1,13 +0,0 @@
import { DIFF, ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs"
import { RollType } from "./roll-type.mjs"
export class RollTypeAttaque extends RollType {
get code() { return ROLL_TYPE_ATTAQUE }
get name() { return `Attaquer` }
title(rollData) { return `attaque` }
onSelect(rollData) {
this.setDiffType(rollData, DIFF.ATTAQUE)
}
}

View File

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

View File

@@ -1,17 +0,0 @@
import { DIFF, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs"
import { RollType } from "./roll-type.mjs"
export class RollTypeDefense extends RollType {
get code() { return ROLL_TYPE_DEFENSE }
get name() { return `Se défendre` }
title(rollData) { return `se défend${rollData.opponent ? ' de' : ''}` }
getOpponent(rollData) {
return rollData.attacker
}
onSelect(rollData) {
this.setDiffType(rollData, DIFF.DEFENSE)
}
}

View File

@@ -1,28 +0,0 @@
import { DIFF, ROLL_TYPE_OEUVRE } from "./roll-constants.mjs"
import { PART_OEUVRE } from "./roll-part-oeuvre.mjs"
import { RollType } from "./roll-type.mjs"
export class RollTypeOeuvre extends RollType {
get code() { return ROLL_TYPE_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.setDiffType(rollData, DIFF.AUCUN)
}
getResult(rollData){
const current = rollData.current[PART_OEUVRE]
const qualite = rollData.rolled.isSuccess ? current.qualite : Math.min(current.qualite, current.comp.system.niveau)
return {
qualite: qualite + rollData.rolled.ptQualite
}
}
}

View File

@@ -1,14 +0,0 @@
import { DIFF, ROLL_TYPE_SORT } from "./roll-constants.mjs"
import { RollType } from "./roll-type.mjs"
export class RollTypeSort extends RollType {
get code() { return ROLL_TYPE_SORT }
get name() { return `lancer un sort` }
visible(rollData) { return rollData.active.actor.isHautRevant() }
title(rollData) { return `lance le sort:` }
onSelect(rollData) {
this.setDiffType(rollData, DIFF.AUCUN)
}
}

View File

@@ -1,59 +0,0 @@
import { DIFF } from "./roll-constants.mjs"
import { PART_DIFF } from "./roll-part-diff.mjs"
const DEFAULT_DIFF_TYPES = [DIFF.LIBRE, DIFF.IMPOSEE, DIFF.DEFAUT]
export class RollType {
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` }
get chatResultTemplate() { return `systems/foundryvtt-reve-de-dragon/templates/roll/result/chat-${this.code}.hbs` }
toTypeData(rollData) {
return { code: this.code, name: this.name, icon: this.icon, section: 'type', template: this.template, selected: this.isSelected(rollData) }
}
isAllowed(rollData) { return rollData.type.allowed == undefined || rollData.type.allowed.includes(this.code) }
visible(rollData) { return true }
title(rollData) { return this.code }
isSelected(rollData) { return rollData.type.current == this.code }
setRollDataType(rollData) {
rollData.type.opposed = rollData.opponent != undefined
rollData.type.resistance = false /** TODO */
}
onSelect(rollData) {
const possibleTypes = [
rollData.current[PART_DIFF].type,
this.typeFromOpponents(rollData),
rollData.selected[PART_DIFF].type
]
const type = possibleTypes.find(m => DEFAULT_DIFF_TYPES.includes(m)) ??DIFF.DEFAUT
this.setDiffType(rollData, type)
}
typeFromOpponents(rollData) {
if (rollData.type.opposed) {
if (rollData.type.resistance) {
return DIFF.IMPOSEE
}
return DIFF.LIBRE
}
return undefined
}
setDiffType(rollData, type) {
rollData.current[PART_DIFF].type = type
this.setRollDataType(rollData)
}
getResult(rollData){
return undefined
}
}

View File

@@ -121,7 +121,7 @@ export const referenceAjustements = {
}, },
tactique: { tactique: {
isUsed: (rollData, actor) => rollData.tactique, isUsed: (rollData, actor) => rollData.tactique,
getLabel: (rollData, actor) => RdDBonus.find(rollData.tactique).label, getLabel: (rollData, actor) => RdDBonus.find(rollData.tactique).descr,
getValue: (rollData, actor) => RdDBonus.find(rollData.tactique).attaque, getValue: (rollData, actor) => RdDBonus.find(rollData.tactique).attaque,
}, },
finesse: { finesse: {
@@ -130,11 +130,11 @@ export const referenceAjustements = {
}, },
surprise: { surprise: {
isUsed: (rollData, actor) => actor.getSurprise(rollData.passeArme), isUsed: (rollData, actor) => actor.getSurprise(rollData.passeArme),
getDescr: (rollData, actor) => RdDBonus.find(actor.getSurprise()).label getDescr: (rollData, actor) => RdDBonus.find(actor.getSurprise()).descr
}, },
attaqueDefenseurSurpris: { attaqueDefenseurSurpris: {
isUsed: (rollData, actor) => rollData.surpriseDefenseur, isUsed: (rollData, actor) => rollData.surpriseDefenseur,
getLabel: (rollData, actor) => RdDBonus.find(rollData.surpriseDefenseur).label + (rollData.attackerRoll ? '' : ' défenseur'), getLabel: (rollData, actor) => RdDBonus.find(rollData.surpriseDefenseur).descr + (rollData.attackerRoll ? '' : ' défenseur'),
getValue: (rollData, actor) => RdDBonus.find(rollData.surpriseDefenseur).attaque, getValue: (rollData, actor) => RdDBonus.find(rollData.surpriseDefenseur).attaque,
}, },
armeParade: { armeParade: {

View File

@@ -2,12 +2,10 @@ import { SYSTEM_RDD } from "../constants.js"
import { Misc } from "../misc.js" import { Misc } from "../misc.js"
export const EXPORT_CSV_SCRIPTARIUM = 'export-csv-scriptarium' export const EXPORT_CSV_SCRIPTARIUM = 'export-csv-scriptarium'
export const ROLL_DIALOG_V2 = 'roll-dialog-v2' export const ROLL_DIALOG_V2 = 'roll-drialog-v2'
export const ROLL_DIALOG_V2_TEST = 'roll-dialog-v2-test'
const OPTIONS_AVANCEES = [ const OPTIONS_AVANCEES = [
{ group: 'Fenêtres', name: ROLL_DIALOG_V2, descr: "Utiliser les nouvelles fenêtres de jet", default: false }, { group: 'Fenêtres', name: ROLL_DIALOG_V2, descr: "Utiliser les nouvelles fenêtres de jet", default: false },
{ group: 'Fenêtres', name: ROLL_DIALOG_V2_TEST, descr: "Mode de test des nouvelles fenêtres", default: false },
{ group: 'Menus', name: EXPORT_CSV_SCRIPTARIUM, descr: "Proposer le menu d'export csv Scriptarium", default: false }, { group: 'Menus', name: EXPORT_CSV_SCRIPTARIUM, descr: "Proposer le menu d'export csv Scriptarium", default: false },
] ]

View File

@@ -13,7 +13,6 @@ const listeReglesOptionnelles = [
{ group: 'Règles de combat', name: 'localisation-aleatoire', descr: "Proposer une localisation aléatoire des blessures" }, { group: 'Règles de combat', name: 'localisation-aleatoire', descr: "Proposer une localisation aléatoire des blessures" },
{ group: 'Règles de combat', name: 'recul', descr: "Appliquer le recul en cas de particulière en force ou de charge" }, { group: 'Règles de combat', name: 'recul', descr: "Appliquer le recul en cas de particulière en force ou de charge" },
{ group: 'Règles de combat', name: 'acrobatie-pour-recul', descr: "L'acrobatie aide à ne pas chuter en cas de recul" , default: false },
{ group: 'Règles de combat', name: 'resistanceArmeParade', descr: "Faire le jet de résistance des armes lors de parades pouvant les endommager" }, { group: 'Règles de combat', name: 'resistanceArmeParade', descr: "Faire le jet de résistance des armes lors de parades pouvant les endommager" },
{ group: 'Règles de combat', name: 'deteriorationArmure', descr: "Tenir compte de la détérioration des armures" }, { group: 'Règles de combat', name: 'deteriorationArmure', descr: "Tenir compte de la détérioration des armures" },
{ group: 'Règles de combat', name: 'defenseurDesarme', descr: "Le défenseur peut être désarmé en parant une particulière en force ou une charge avec une arme autre qu'un bouclier" }, { group: 'Règles de combat', name: 'defenseurDesarme', descr: "Le défenseur peut être désarmé en parant une particulière en force ou une charge avec une arme autre qu'un bouclier" },

View File

@@ -1,6 +1,4 @@
import { SYSTEM_RDD } from "../constants.js"; import { SYSTEM_RDD } from "../constants.js";
import { Misc } from "../misc.js";
import { RdDBonus } from "../rdd-bonus.js";
export const STATUSES = { export const STATUSES = {
StatusGrappling: 'grappling', StatusGrappling: 'grappling',
@@ -14,11 +12,9 @@ export const STATUSES = {
StatusBleeding: 'bleeding', StatusBleeding: 'bleeding',
StatusDead: 'dead', StatusDead: 'dead',
StatusDemiReve: 'demi-reve', StatusDemiReve: 'demi-reve',
StatusForceWeak: 'force insuffisante',
} }
const forceWeakStatusEffect = { rdd: true, id: STATUSES.StatusForceWeak, name: 'EFFECT.StatusForceWeak', img: 'systems/foundryvtt-reve-de-dragon/assets/actions/weak.svg' }; const demiReveStatusEffect = { rdd: true, id: STATUSES.StatusDemiReve, name: 'EFFECT.StatusDemiReve', img: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd12.svg' };
const demiReveStatusEffect = { rdd: true, id: STATUSES.StatusDemiReve, name: 'EFFECT.StatusDemiReve', img: 'systems/foundryvtt-reve-de-dragon/assets/actions/sort.svg' };
const rddStatusEffects = [ const rddStatusEffects = [
{ rdd: true, id: STATUSES.StatusGrappling, tint: '#33cc33', name: 'EFFECT.StatusGrappling', img: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.webp' }, { rdd: true, id: STATUSES.StatusGrappling, tint: '#33cc33', name: 'EFFECT.StatusGrappling', img: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.webp' },
{ rdd: true, id: STATUSES.StatusGrappled, tint: '#ff9900', name: 'EFFECT.StatusGrappled', img: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.webp' }, { rdd: true, id: STATUSES.StatusGrappled, tint: '#ff9900', name: 'EFFECT.StatusGrappled', img: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.webp' },
@@ -33,15 +29,15 @@ const rddStatusEffects = [
{ rdd: true, id: STATUSES.StatusBleeding, name: 'EFFECT.StatusBleeding', img: 'icons/svg/blood.svg' }, { rdd: true, id: STATUSES.StatusBleeding, name: 'EFFECT.StatusBleeding', img: 'icons/svg/blood.svg' },
{ rdd: true, id: STATUSES.StatusDead, name: 'EFFECT.StatusDead', img: 'icons/svg/skull.svg' }, { rdd: true, id: STATUSES.StatusDead, name: 'EFFECT.StatusDead', img: 'icons/svg/skull.svg' },
demiReveStatusEffect, demiReveStatusEffect
forceWeakStatusEffect
]; ];
const statusDemiSurprise = new Set([STATUSES.StatusStunned, STATUSES.StatusProne, STATUSES.StatusRestrained, STATUSES.StatusForceWeak]) const statusDemiSurprise = new Set([STATUSES.StatusStunned, STATUSES.StatusProne, STATUSES.StatusRestrained])
const statusSurpriseTotale = new Set([STATUSES.StatusUnconscious, STATUSES.StatusBlind, STATUSES.StatusComma]) const statusSurpriseTotale = new Set([STATUSES.StatusUnconscious, STATUSES.StatusBlind, STATUSES.StatusComma])
export class StatusEffects extends FormApplication { export class StatusEffects extends FormApplication {
static onReady() { static onReady() {
const rddEffectIds = rddStatusEffects.map(it => it.id); const rddEffectIds = rddStatusEffects.map(it => it.id);
rddStatusEffects.forEach(it => { rddStatusEffects.forEach(it => {
@@ -71,27 +67,6 @@ export class StatusEffects extends FormApplication {
console.log('statusEffects', CONFIG.statusEffects); console.log('statusEffects', CONFIG.statusEffects);
} }
static isSurprise(effect) {
return StatusEffects.niveauSurprise(effect, true) > 0
}
static getSurprise(effects, isCombat = undefined) {
return StatusEffects.typeSurprise(
effects.map(it => StatusEffects.niveauSurprise(it, isCombat))
.reduce(Misc.sum(), 0)
)
}
static getActorEffetSurprise(actor, forceRequise) {
const effets = actor?.getEffects(StatusEffects.isSurprise, forceRequise) ?? []
return {
effets: effets,
surprise: effets.length > 0
? RdDBonus.find(StatusEffects.getSurprise(effets, true))
: undefined
}
}
static niveauSurprise(effect, isCombat) { static niveauSurprise(effect, isCombat) {
if (statusSurpriseTotale.intersects(effect.statuses)) { if (statusSurpriseTotale.intersects(effect.statuses)) {
return 2 return 2

View File

@@ -7,7 +7,9 @@
<span class="initiative-value">Initiative</span> <span class="initiative-value">Initiative</span>
</li> </li>
{{#each combat as |action key|}} {{#each combat as |action key|}}
<li class="item flexrow list-item" data-item-id="{{action._id}}" data-arme-name="{{action.arme.name}}" <li class="item flexrow list-item"
data-item-id="{{action._id}}"
data-arme-name="{{action.arme.name}}"
data-competence-name="{{action.comp.name}}" data-competence-name="{{action.comp.name}}"
data-tooltip="{{action.name}}: niveau {{plusMoins action.comp.system.niveau}}"> data-tooltip="{{action.name}}: niveau {{plusMoins action.comp.system.niveau}}">
<span class="list-item-label flexrow"> <span class="list-item-label flexrow">
@@ -21,10 +23,11 @@
{{>"systems/foundryvtt-reve-de-dragon/templates/item/icon-arme-broken.hbs" action.arme}} {{>"systems/foundryvtt-reve-de-dragon/templates/item/icon-arme-broken.hbs" action.arme}}
</span> </span>
<span class="competence-value">{{plusMoins action.comp.system.niveau}}</span> <span class="competence-value">{{plusMoins action.comp.system.niveau}}</span>
<span class="competence-value">{{plusMoins action.dommagesArme}}</span> <span class="competence-value">{{plusMoins action.dmg}}</span>
<span class="competence-value"></span> <span class="competence-value"></span>
<span class="initiative-value"> <span class="initiative-value">
<a class="roll-init-arme" data-tooltip="{{action.name}}: initiative {{action.initiative}}"> <a class="roll-init-arme"
data-tooltip="{{action.name}}: initiative {{action.initiative}}">
{{action.initiative}} {{action.initiative}}
</a> </a>
</span> </span>
@@ -54,7 +57,8 @@
<span class="item-controls"></span> <span class="item-controls"></span>
</li> </li>
{{#each empoignades as |emp key|}} {{#each empoignades as |emp key|}}
<li class="item flexrow list-item" data-item-id="{{emp._id}}" data-arme-name="{{emp.name}}" <li class="item flexrow list-item"
data-item-id="{{emp._id}}" data-arme-name="{{emp.name}}"
data-tooltip="{{emp.name}}: niveau {{plusMoins emp.system.pointsemp}}"> data-tooltip="{{emp.name}}: niveau {{plusMoins emp.system.pointsemp}}">
<a class="flex-grow-3 action-empoignade"> <a class="flex-grow-3 action-empoignade">
<img class="sheet-competence-img" src="{{emp.img}}"/> <img class="sheet-competence-img" src="{{emp.img}}"/>

View File

@@ -16,7 +16,7 @@
{{/if}} {{/if}}
{{/unless}} {{/unless}}
</span> </span>
<ul class="item-list alterne-list liste-equipement"> <ul class="item-list alterne-list">
<li class="competence-header flexrow"> <li class="competence-header flexrow">
<span class="equipement-nom">Nom</span> <span class="equipement-nom">Nom</span>
{{#unless system.illimite}} {{#unless system.illimite}}

View File

@@ -15,7 +15,7 @@
&hyphen; Valeur: {{numberFormat calc.prixTotalEquipement decimals=2}} Sols &hyphen; Valeur: {{numberFormat calc.prixTotalEquipement decimals=2}} Sols
{{/if}} {{/if}}
</span> </span>
<ul class="item-list alterne-list liste-equipement"> <ul class="item-list alterne-list">
<li class="competence-header flexrow"> <li class="competence-header flexrow">
<span class="equipement-nom">Nom</span> <span class="equipement-nom">Nom</span>
<span class="equipement-detail-buttons">Q.</span> <span class="equipement-detail-buttons">Q.</span>

View File

@@ -1,11 +1,5 @@
<div data-passearme="{{passeArme}}"> <div data-passearme="{{passeArme}}">
<h4 class="rdd-roll-etotal">Maladresse à l'attaque:<br>échec <h4 class="rdd-roll-etotal"><strong>Echec total en attaque</strong></h4>
{{#if rolled.isETotal}}
total
{{else}}
en demi-surprise
{{/if}}
</h4>
<br> <br>
{{#if (eq attacker.type 'personnage')}} {{#if (eq attacker.type 'personnage')}}
{{#unless essais.attaqueChance}} {{#unless essais.attaqueChance}}

View File

@@ -22,36 +22,21 @@
{{#if (eq defender.type 'personnage')}} {{#if (eq defender.type 'personnage')}}
<a class='chat-card-button appel-chance-defense' <a class='chat-card-button appel-chance-defense'
data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}'> data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}'>
Faire appel à la chance Faire appel à la chance</a>
</a> </a>
<br> <br>
{{/if}} {{/if}}
{{#if (and (eq defender.type 'personnage') (gt defender.system.compteurs.destinee.value 0))}} {{#if (and (eq defender.type 'personnage') (gt defender.system.compteurs.destinee.value 0))}}
<a class='chat-card-button appel-destinee-defense' <a class='chat-card-button appel-destinee-defense'
data-attackerId='{{attackerId}}' data-attackerTokenId='{{attackerToken.id}}' data-defenderTokenId='{{defenderToken.id}}'> data-attackerId='{{attackerId}}' data-attackerTokenId='{{attackerToken.id}}' data-defenderTokenId='{{defenderToken.id}}'>
Utiliser la destinée Utiliser la destinée</a>
</a> </a>
<br> <br>
{{/if}} {{/if}}
{{/unless}} {{/unless}}
{{else}}
{{#if (settings-get 'rdd-advanced-roll-dialog-v2')}}
<a class='chat-card-button button-defense'
data-attackerId='{{attackerId}}'
data-attackerTokenId='{{attackerToken.id}}'
data-defenderTokenId='{{defenderToken.id}}'
>
Se défendre
{{#if (or (eq attaqueCategorie 'tir') (eq attaqueCategorie 'lancer'))}}
(difficulté à déterminer)
{{else}}
à {{diffLibre }}
{{/if}}
</a>
<br>
{{else}} {{else}}
{{#each armes as |arme key|}} {{#each armes as |arme key|}}
<a class='chat-card-button button-parade' <a class='chat-card-button parer-button'
data-attackerId='{{../attackerId}}' data-defenderTokenId='{{../defenderToken.id}}' data-attackerTokenId='{{../attackerToken.id}}' data-attackerId='{{../attackerId}}' data-defenderTokenId='{{../defenderToken.id}}' data-attackerTokenId='{{../attackerToken.id}}'
data-armeid='{{arme._id}}'> data-armeid='{{arme._id}}'>
Parer avec {{arme.name}} Parer avec {{arme.name}}
@@ -67,7 +52,7 @@
<br> <br>
{{/each}} {{/each}}
{{#if mainsNues}} {{#if mainsNues}}
<a class='chat-card-button button-parade' <a class='chat-card-button parer-button'
data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}' data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}'
data-armeid='{{arme._id}}' data-competence='{{arme.system.competence}}'> data-armeid='{{arme._id}}' data-competence='{{arme.system.competence}}'>
Parer à mains nues à {{diffLibre}}{{#if arme.nbUsage}} (Utilisations : {{arme.nbUsage}}){{/if}} Parer à mains nues à {{diffLibre}}{{#if arme.nbUsage}} (Utilisations : {{arme.nbUsage}}){{/if}}
@@ -76,7 +61,7 @@
{{/if}} {{/if}}
{{#if (ne attaqueCategorie 'tir')}} {{#if (ne attaqueCategorie 'tir')}}
{{#each esquives as |esquive key|}} {{#each esquives as |esquive key|}}
<a class='chat-card-button button-esquive' <a class='chat-card-button esquiver-button'
data-attackerId='{{../attackerId}}' data-defenderTokenId='{{../defenderToken.id}}' data-attackerTokenId='{{../attackerToken.id}}' data-attackerId='{{../attackerId}}' data-defenderTokenId='{{../defenderToken.id}}' data-attackerTokenId='{{../attackerToken.id}}'
data-compid='{{esquive._id}}' data-competence='{{esquive.name}}'> data-compid='{{esquive._id}}' data-competence='{{esquive.name}}'>
{{esquive.name}} {{esquive.name}}
@@ -90,9 +75,8 @@
{{/each}} {{/each}}
{{/if}} {{/if}}
{{/if}} {{/if}}
{{/if}}
{{/unless}} {{/unless}}
<a class='chat-card-button button-encaisser' <a class='chat-card-button encaisser-button'
data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}'> data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}'>
Encaisser à {{plusMoins dmg.total}} Encaisser à {{plusMoins dmg.total}}
{{#if (eq dmg.mortalite 'non-mortel')~}} {{#if (eq dmg.mortalite 'non-mortel')~}}

View File

@@ -2,12 +2,13 @@
<span {{#if ajustements}}class="tooltip-overflow tooltip-dotted" {{/if}}> <span {{#if ajustements}}class="tooltip-overflow tooltip-dotted" {{/if}}>
<span> <span>
<span>{{rolled.caracValue}} à {{plusMoins rolled.finalLevel}}</span> <span>{{rolled.caracValue}} à {{plusMoins rolled.finalLevel}}</span>
{{#if (and rolled.factorHtml (gt rolled.factorHtml 1))}} {{#if ajustements}}
<span class="rdd-diviseur">&times;{{{rolled.factorHtml}}}</span> {{/if}}
{{log this}}
{{#if rolled.factorHtml}}<span class="rdd-diviseur">&times;{{{rolled.factorHtml}}}</span>{{/if}}
<span>= {{rolled.score}}%</span> <span>= {{rolled.score}}%</span>
{{#if rolled.factorHtml}}
<span class="rdd-diviseur">&times;{{{rolled.factorHtml}}}</span> <span class="rdd-diviseur">&times;{{{rolled.factorHtml}}}</span>
{{else}}
<span>= {{rolled.score}}%</span>
{{/if}} {{/if}}
</span> </span>
<div class="tooltiptext ttt-ajustements"> <div class="tooltiptext ttt-ajustements">

View File

@@ -37,8 +37,8 @@
{{#if encaissement.dmg.dmgSurprise}} {{#if encaissement.dmg.dmgSurprise}}
<div>+dom surprise: {{plusMoins encaissement.dmg.dmgSurprise}}</div> <div>+dom surprise: {{plusMoins encaissement.dmg.dmgSurprise}}</div>
{{/if}} {{/if}}
{{#if encaissement.dmg.dmgDiffLibre}} {{#if encaissement.dmg.bonusDegatsDiffLibre}}
<div>+dom attaque: {{plusMoins encaissement.dmg.dmgDiffLibre}}</div> <div>+dom attaque: {{plusMoins encaissement.dmg.bonusDegatsDiffLibre}}</div>
{{/if}} {{/if}}
</div> </div>
</span> </span>

View File

@@ -15,7 +15,7 @@
{{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.hbs"}} {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.hbs"}}
{{#if options.isOwned}} {{#if options.isOwned}}
<div class="flexcol"> <div class="flexcol">
<ul class="item-list alterne-list liste-equipement"> <ul class="item-list alterne-list">
<li class="competence-header flexrow"> <li class="competence-header flexrow">
<span class="equipement-nom">Nom</span> <span class="equipement-nom">Nom</span>
<span class="equipement-detail">Q.</span> <span class="equipement-detail">Q.</span>

View File

@@ -1,53 +0,0 @@
{{log this}}
<div class="roll-chat">
<div class="chat-img">
<img src="{{active.img}}" data-tooltip="{{active.name}}" />
<img src="{{competence.img}}" data-tooltip="{{competence.name}}" />
</div>
<div class="chat-header">
{{active.name}} {{#if current.defense.isEsquive}}esquive{{else}}pare{{/if}} une attaque {{grammar-apostrophe 'de' opponent.name}}
</div>
<div class="chat-resume">
{{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}}
<br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}}
</div>
<div class="chat-details">
<hr>
{{#if rolled.isSuccess}}
<p>
Attaque {{#if current.defense.isEsquive}}esquivée{{else}}parée{{/if}}
{{#if rolled.isPart}}, {{active.name}} peut
<strong>{{#if current.defense.isEsquive}}faire une deuxième esquive{{else}}réutiliser son arme{{/if}}</strong>
{{/if}}
</p>
{{else}}
<p>{{#if current.defense.isEsquive}}Esquive{{else}}parade{{/if}} échouée!</p>
{{/if}}
{{!-- {{else}}
<!-- TODO: cas de parade à mains nues, texte à modifier -->
{{/if}} --}}
{{#if attackerRoll.tactique}}
<p>
{{#if (eq attackerRoll.tactique.key 'charge')}}
<img class="chat-icon" src="icons/svg/thrust.svg" data-tooltip="charge" height="32" width="32" />
C'était une charge, les parades de {{opponent.name}} auront un -4 et il ne pourra pas esquiver!
{{else if (eq attackerRoll.tactique.key 'feinte')}}
<img class="chat-icon" src="systems/foundryvtt-reve-de-dragon/icons/heures/hd06.svg" data-tooltip="feinte" height="32" width="32" />
C'était une feinte!
{{/if}}
</p>
{{/if}}
{{> 'partial-info-appel-moral'}}
</div>
<div class="chat-actions">
{{> 'partial-recul-choc'}}
{{> 'partial-encaissement'}}
</div>
<div class="chat-buttons">
{{> 'partial-appel-chance'}}
</div>
</div>

View File

@@ -1,30 +0,0 @@
{{log this}}
<div class="roll-chat">
<div class="chat-img">
<img src="{{active.img}}" data-tooltip="{{active.name}}" />
<img src="{{competence.img}}" data-tooltip="{{competence.name}}" />
</div>
<div class="chat-header">
{{active.name}} {{current.oeuvre.art.action}}: {{current.oeuvre.label}} (de niveau {{current.oeuvre.oeuvre.system.niveau}})
</div>
<div class="chat-resume">
{{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}}
<br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}}
</div>
<div class="chat-details">
<p>
{{active.name}}
{{#if rolled.isSuccess}}réussit son interprétation avec
{{else}}manque d'inspiration, son interprétation a
{{/if}}
une qualité de {{result.qualite}}.
</p>
{{> 'partial-info-appel-moral'}}
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-description.hbs" current.oeuvre.oeuvre.system}}
</div>
<div class="chat-buttons">
{{> 'partial-appel-chance'}}
</div>
</div>

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