Compare commits
15 Commits
5d8da860c4
...
13.0.9
Author | SHA1 | Date | |
---|---|---|---|
1360992daa | |||
878645491d | |||
edfaf203f7 | |||
3480b64d75 | |||
17e10d3be9 | |||
bbcd6ad363 | |||
faca73b0a1 | |||
a7e14736e4 | |||
2741fc3fbf | |||
160f10a639 | |||
d26ab59c51 | |||
1f330c734e | |||
74515d28f4 | |||
c84af21c7e | |||
0730bdf240 |
66
assets/actions/weak.svg
Normal file
66
assets/actions/weak.svg
Normal file
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 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>
|
After Width: | Height: | Size: 2.7 KiB |
126
assets/ui/chance.svg
Normal file
126
assets/ui/chance.svg
Normal file
@@ -0,0 +1,126 @@
|
||||
<?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>
|
After Width: | Height: | Size: 7.6 KiB |
90
assets/ui/destinee.svg
Normal file
90
assets/ui/destinee.svg
Normal file
@@ -0,0 +1,90 @@
|
||||
<?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>
|
After Width: | Height: | Size: 4.1 KiB |
66
assets/ui/encaisser.svg
Normal file
66
assets/ui/encaisser.svg
Normal file
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 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>
|
After Width: | Height: | Size: 2.7 KiB |
66
assets/ui/recul.svg
Normal file
66
assets/ui/recul.svg
Normal file
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 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>
|
After Width: | Height: | Size: 3.7 KiB |
21
changelog.md
21
changelog.md
@@ -3,11 +3,28 @@
|
||||
## 13.0.9 - Le combat d'Illysis
|
||||
- Fix
|
||||
- La montée en TMR fonctionne
|
||||
- ajout d'un status "Force insuffisante"
|
||||
- clarification des maladresses à l'attaque (en demi surprise, ou à cause d'un échec total)
|
||||
- Nouvelle fenêtre de jets de dés
|
||||
- ajout du statut "Force insuffisante" aux acteurs si la
|
||||
force est insuffisante pour l'arme
|
||||
- avancement du mode attaque
|
||||
- choix de tactique
|
||||
- choix des dommages, affichage
|
||||
- affichage de la surprise du défenseur
|
||||
- choix mortel/non-mortel pour les dommages
|
||||
- affichage des dommages ajustés delon les choix
|
||||
- affichage du statut de surprise de l'attaquant
|
||||
- affichage du statut de surprise du défenseur
|
||||
- prise en compte des significatives (demi-surprises)
|
||||
- avancement du mode défense
|
||||
- sélection esquive/parade
|
||||
- affichage du statut de surprise du défenseur
|
||||
- prise en compte des significatives (demi-surprises, armes disparates,
|
||||
particulière en finesse)
|
||||
- gestion de l'appel à la chance
|
||||
- gestion de l'utilisation de la destinée
|
||||
- gestion du recul depuis le messages
|
||||
- gestion de l'encaissement depuis le messages
|
||||
- impossible de faire un jet "actif" en surprise totale (attaque, parade, ...)
|
||||
|
||||
## 13.0.8 - Le renouveau d'Illysis
|
||||
|
||||
|
@@ -424,7 +424,7 @@ select,
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog {
|
||||
font-family: CaslonAntique;
|
||||
display: grid;
|
||||
grid-template-areas: "header header header header header header header" "action action action action action action action" "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-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-columns: 2rem 1rem 1fr 1fr 2fr 2fr 3fr;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
@@ -450,7 +450,7 @@ select,
|
||||
grid-area: resolution;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions {
|
||||
grid-area: modifiers;
|
||||
grid-area: conditions;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-chances {
|
||||
grid-area: chances;
|
||||
@@ -461,26 +461,26 @@ select,
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-buttons {
|
||||
grid-area: buttons;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-mode {
|
||||
grid-area: mode;
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-type {
|
||||
grid-area: type;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="rollmode"] button[data-checked="true"],
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-mode button[data-checked="true"] {
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-type button[data-checked="true"] {
|
||||
background-color: var(--color-text-selection-bg);
|
||||
color: var(--color-controls);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="rollmode"] button[data-checked="true"] i,
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-mode button[data-checked="true"] i {
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-type button[data-checked="true"] i {
|
||||
filter: invert(0.8);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="rollmode"] button[data-checked="true"] img,
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-mode button[data-checked="true"] img {
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-type button[data-checked="true"] img {
|
||||
filter: invert(0.2);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="rollmode"] button,
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-mode button {
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-type button {
|
||||
height: 1.8rem;
|
||||
width: 1.8rem;
|
||||
gap: 0.5rem;
|
||||
@@ -489,11 +489,11 @@ select,
|
||||
color: var(--color-controls);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="rollmode"] button i,
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-mode button i {
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-type button i {
|
||||
filter: invert(0.2);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="rollmode"] button img,
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-mode button img {
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-type button img {
|
||||
filter: invert(0.8);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog :is(roll-carac, roll-comp) {
|
||||
@@ -556,6 +556,17 @@ select,
|
||||
display: flex;
|
||||
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 {
|
||||
display: flow;
|
||||
width: 2.5rem;
|
||||
@@ -644,6 +655,80 @@ select,
|
||||
width: 1.5rem;
|
||||
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 {
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
@@ -932,16 +1017,18 @@ select,
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .flex-grow,
|
||||
.system-foundryvtt-reve-de-dragon .flex-grow-3 {
|
||||
display: flex;
|
||||
flex-grow: 3;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .flex-grow-2 {
|
||||
flex-grow: 2;
|
||||
.system-foundryvtt-reve-de-dragon .flex-grow-0-5 {
|
||||
flex-grow: 0.5;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .flex-grow-1 {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .flex-grow-0-5 {
|
||||
flex-grow: 0.5;
|
||||
.system-foundryvtt-reve-de-dragon .flex-grow-2 {
|
||||
display: flex;
|
||||
flex-grow: 2;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .voyage-liste-survies {
|
||||
max-width: 12rem;
|
||||
@@ -984,14 +1071,16 @@ select,
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .item-actions-controls,
|
||||
.system-foundryvtt-reve-de-dragon .equipement-actions {
|
||||
.system-foundryvtt-reve-de-dragon :is(.item-actions-controls, .equipement-actions) {
|
||||
margin: 0;
|
||||
flex-grow: 2;
|
||||
flex-grow: 1.2;
|
||||
align-items: end;
|
||||
justify-content: flex-end;
|
||||
text-align: right;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .liste-equipement :is(.equipement-actions, .item-actions-controls) {
|
||||
flex-grow: 2;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .blessure-control {
|
||||
flex-grow: 1;
|
||||
flex-direction: row;
|
||||
@@ -1225,15 +1314,6 @@ select,
|
||||
margin-right: 0.2rem;
|
||||
margin-left: 0.2rem;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .flex-grow-1 {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .flex-grow-2 {
|
||||
flex-grow: 2;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .flex-grow-3 {
|
||||
flex-grow: 3;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon fieldset {
|
||||
border-style: groove;
|
||||
border-width: 0.1rem;
|
||||
@@ -1980,11 +2060,13 @@ select,
|
||||
flex-grow: 2;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon #sidebar {
|
||||
font-size: 1rem;
|
||||
background: #695541 url(../assets/ui/bg_sid_dark.webp) no-repeat right bottom;
|
||||
background-position: 100%;
|
||||
color: rgba(220, 220, 220, 0.75);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon #sidebar .chat-message {
|
||||
font-size: 1rem;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon #sidebar-tabs > .collapsed,
|
||||
.system-foundryvtt-reve-de-dragon #chat-controls .chat-control-icon {
|
||||
color: rgba(220, 220, 220, 0.75);
|
||||
@@ -2595,6 +2677,22 @@ select,
|
||||
border: 2px ridge #846109;
|
||||
display: inline-block;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .chat-card-button img,
|
||||
.system-foundryvtt-reve-de-dragon .chat-card-button-pushed img {
|
||||
max-width: 1rem;
|
||||
max-height: 1rem;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .chat-card-info {
|
||||
font-size: 1.1rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .chat-card-info img {
|
||||
margin: 0 0.5rem;
|
||||
max-width: 1rem;
|
||||
max-height: 1rem;
|
||||
filter: invert(0.8);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .chat-card-button {
|
||||
text-shadow: 1px 1px #4d3534;
|
||||
box-shadow: inset 1x 1px #a6827e;
|
||||
|
@@ -66,6 +66,7 @@
|
||||
"StatusRestrained": "Immobilisé",
|
||||
"StatusComma": "Comma",
|
||||
"StatusDead": "Mort",
|
||||
"StatusDemiReve": "Demi-rêve"
|
||||
"StatusDemiReve": "Demi-rêve",
|
||||
"StatusForceWeak": "Force insuffisante"
|
||||
}
|
||||
}
|
@@ -7,6 +7,7 @@
|
||||
@import "item/munition.less";
|
||||
@import "item/tarot.less";
|
||||
@import "roll-dialog.less";
|
||||
@import "roll-chat.less";
|
||||
.window-header{
|
||||
background: rgba(0,0,0,0.75);
|
||||
}
|
||||
@@ -333,16 +334,18 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.flex-grow, .flex-grow-3 {
|
||||
display: flex;
|
||||
flex-grow: 3;
|
||||
}
|
||||
.flex-grow-2 {
|
||||
flex-grow: 2;
|
||||
.flex-grow-0-5 {
|
||||
flex-grow: 0.5;
|
||||
}
|
||||
.flex-grow-1 {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.flex-grow-0-5 {
|
||||
flex-grow: 0.5;
|
||||
.flex-grow-2 {
|
||||
display: flex;
|
||||
flex-grow: 2;
|
||||
}
|
||||
.voyage-liste-survies {
|
||||
max-width: 12rem;
|
||||
@@ -386,14 +389,16 @@
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
.item-actions-controls,
|
||||
.equipement-actions {
|
||||
:is(.item-actions-controls, .equipement-actions) {
|
||||
margin: 0;
|
||||
flex-grow: 2;
|
||||
flex-grow: 1.2;
|
||||
align-items: end;
|
||||
justify-content: flex-end;
|
||||
text-align: right;
|
||||
}
|
||||
.liste-equipement :is(.equipement-actions, .item-actions-controls) {
|
||||
flex-grow: 2;
|
||||
}
|
||||
|
||||
.blessure-control {
|
||||
flex-grow: 1;
|
||||
@@ -622,16 +627,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.flex-grow-1 {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.flex-grow-2 {
|
||||
flex-grow: 2;
|
||||
}
|
||||
.flex-grow-3 {
|
||||
flex-grow: 3;
|
||||
}
|
||||
fieldset {
|
||||
border-style: groove;
|
||||
border-width: 0.1rem;
|
||||
@@ -1451,7 +1446,9 @@
|
||||
/* ======================================== */
|
||||
/* Sidebar CSS */
|
||||
#sidebar {
|
||||
font-size: 1rem;
|
||||
.chat-message{
|
||||
font-size: 1rem;
|
||||
}
|
||||
background: rgb(105,85,65) url(../assets/ui/bg_sid_dark.webp) no-repeat right bottom;
|
||||
background-position: 100%;
|
||||
color: rgba(220,220,220,0.75);
|
||||
@@ -1961,7 +1958,23 @@
|
||||
|
||||
border: 2px ridge #846109;
|
||||
display: inline-block;
|
||||
img {
|
||||
max-width: 1rem;
|
||||
max-height: 1rem;
|
||||
}
|
||||
}
|
||||
.chat-card-info{
|
||||
font-size: 1.1rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
img {
|
||||
margin: 0 0.5rem;
|
||||
max-width: 1rem;
|
||||
max-height: 1rem;
|
||||
filter: invert(0.8);
|
||||
}
|
||||
}
|
||||
|
||||
.chat-card-button{
|
||||
text-shadow: 1px 1px #4d3534;
|
||||
|
87
less/roll-chat.less
Normal file
87
less/roll-chat.less
Normal file
@@ -0,0 +1,87 @@
|
||||
.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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@@ -4,11 +4,11 @@
|
||||
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"
|
||||
"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-columns: 2rem 1rem 1fr 1fr 2fr 2fr 3fr;
|
||||
gap: 0.2rem;
|
||||
@@ -22,18 +22,18 @@
|
||||
roll-choix { grid-area: choix; }
|
||||
|
||||
roll-table { grid-area: resolution; }
|
||||
roll-conditions { grid-area: modifiers; }
|
||||
roll-conditions { grid-area: conditions; }
|
||||
roll-chances { grid-area: chances; }
|
||||
roll-resume { grid-area: resume; }
|
||||
roll-buttons { grid-area: buttons; }
|
||||
|
||||
roll-mode {
|
||||
grid-area: mode;
|
||||
roll-type {
|
||||
grid-area: type;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
roll-conditions roll-section[name="rollmode"],
|
||||
roll-mode {
|
||||
roll-type {
|
||||
button[data-checked="true"] {
|
||||
background-color: var(--color-text-selection-bg);
|
||||
color: var(--color-controls);
|
||||
@@ -95,7 +95,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
grid-area: img;
|
||||
img{
|
||||
img {
|
||||
border: 0;
|
||||
padding: 1px;
|
||||
max-height: 3rem;
|
||||
@@ -118,6 +118,17 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
span.status-surprise{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-flow: wrap;
|
||||
img {
|
||||
filter: invert(0.8);
|
||||
}
|
||||
}
|
||||
label {
|
||||
align-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -11,7 +11,6 @@ import { MAINS_DIRECTRICES } from "./actor.js";
|
||||
import { RdDBaseActorReveSheet } from "./actor/base-actor-reve-sheet.js";
|
||||
import { ITEM_TYPES } from "./constants.js";
|
||||
import { RdDItem } from "./item.js";
|
||||
import { RdDItemArme } from "./item/arme.js";
|
||||
import { RdDItemCompetence } from "./item-competence.js";
|
||||
import { RdDItemBlessure } from "./item/blessure.js";
|
||||
import { RdDEmpoignade } from "./rdd-empoignade.js";
|
||||
|
@@ -31,7 +31,7 @@ export class ActorToken {
|
||||
|
||||
constructor(token) {
|
||||
this.name = token.name ?? token.actor.name
|
||||
this.img = token.texture.src ?? token.actor.img
|
||||
this.img = token.actor.isToken && token.texture.src ? token.texture.src : token.actor.img
|
||||
this.actor = token.actor
|
||||
this.id = token.actor?.id
|
||||
this.token = token
|
||||
|
199
module/actor.js
199
module/actor.js
@@ -14,7 +14,7 @@ import { STATUSES } from "./settings/status-effects.js";
|
||||
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
||||
import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
|
||||
import { Draconique } from "./tmr/draconique.js";
|
||||
import { LIST_CARAC_PERSONNAGE, RdDCarac } from "./rdd-carac.js";
|
||||
import { CARACS, LIST_CARAC_PERSONNAGE, RdDCarac } from "./rdd-carac.js";
|
||||
import { DialogConsommer } from "./dialog-item-consommer.js";
|
||||
import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js";
|
||||
import { RollDataAjustements } from "./rolldata-ajustements.js";
|
||||
@@ -31,9 +31,8 @@ import { ITEM_TYPES } from "./constants.js";
|
||||
import { RdDBaseActorSang } from "./actor/base-actor-sang.js";
|
||||
import { RdDCoeur } from "./coeur/rdd-coeur.js";
|
||||
import { DialogChoixXpCarac } from "./dialog-choix-xp-carac.js";
|
||||
import { RdDCombatManager } from "./rdd-combat.js";
|
||||
|
||||
import { RdDItemArme } from "./item/arme.js";
|
||||
import { ATTAQUE_TYPE, RdDItemArme } from "./item/arme.js";
|
||||
import { RdDItemBlessure } from "./item/blessure.js";
|
||||
import { RdDItemTete } from "./item/tete.js";
|
||||
import { RdDItemSort } from "./item-sort.js";
|
||||
@@ -47,7 +46,7 @@ import { PAS_DE_DRACONIC, POSSESSION_SANS_DRACONIC } from "./item/base-items.js"
|
||||
import { RdDRollResult } from "./rdd-roll-result.js";
|
||||
import { RdDInitiative } from "./initiative.mjs";
|
||||
import RollDialog from "./roll/roll-dialog.mjs";
|
||||
import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js";
|
||||
import { OptionsAvancees, ROLL_DIALOG_V2, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js";
|
||||
|
||||
export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre']
|
||||
|
||||
@@ -167,63 +166,63 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
.find(it => true)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** Retourne une liste triée d'actions d'armes avec le split arme1 main / arme 2 main / lancer */
|
||||
listActionsAttaque() {
|
||||
let actions = [
|
||||
this.$prepareAttaqueArme(RdDItemArme.empoignade(this)),
|
||||
this.$prepareAttaqueArme(RdDItemArme.corpsACorps(this)),
|
||||
]
|
||||
|
||||
const armes = this.itemTypes[ITEM_TYPES.arme]
|
||||
.filter(it => RdDItemArme.isAttaque(it))
|
||||
.sort(Misc.ascending(it => it.name));
|
||||
|
||||
for (const arme of armes) {
|
||||
if (arme.system.unemain && arme.system.competence) {
|
||||
actions.push(this.$prepareAttaqueArme(arme, '(1 main)'))
|
||||
}
|
||||
if (arme.system.deuxmains && arme.system.competence) {
|
||||
actions.push(this.$prepareAttaqueArme(arme, '(2 mains)'))
|
||||
}
|
||||
if (arme.system.lancer) {
|
||||
actions.push(this.$prepareAttaqueArme(arme, '(lancer)'))
|
||||
}
|
||||
if (arme.system.tir) {
|
||||
actions.push(this.$prepareAttaqueArme(arme, '(tir)'))
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
isForceInsuffisante(forceRequise) {
|
||||
const force = parseInt(this.system.carac.force.value)
|
||||
return forceRequise > force
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
$prepareAttaqueArme(arme, main) {
|
||||
const comp = this.getCompetence(RdDActor.$getCompetenceAction(arme, main))
|
||||
const caracCode = RdDActor.$getCaracAction(comp, main)
|
||||
const caracValue = this.system.carac[caracCode].value
|
||||
const dommages = arme.system.dommages.toString()
|
||||
/** Retourne une liste triée d'actions d'armes avec le split arme1 main / arme 2 main / lancer */
|
||||
listActionsAttaque() {
|
||||
const actions = []
|
||||
const uniques = []
|
||||
|
||||
// TODO: déplacer sur RdDItemArme
|
||||
if (arme.system.unemain && arme.system.deuxmains && !dommages.includes("/")) {
|
||||
ui.notifications.info(`Les dommages de l'arme à 1/2 mains ${arme.name} ne sont pas corrects (ie sous la forme X/Y)`)
|
||||
}
|
||||
const tableauDommages = dommages.includes("/") ? dommages.split("/") : [dommages, dommages]
|
||||
const dommagesArme = parseInt(main == '(2 mains)' ? tableauDommages[1] : tableauDommages[0])
|
||||
const niveau = comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(main) ? -8 : -6)
|
||||
const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + (arme.system.magique) ? arme.system.ecaille_efficacite : 0
|
||||
const addAttaque = (arme, main) => {
|
||||
const dommagesArme = RdDItemArme.valeurMain(arme.system.dommages, main)
|
||||
const forceRequise = RdDItemArme.valeurMain(arme.system.force ?? 0, main)
|
||||
const ecaillesEfficacite = arme.system.magique ? arme.system.ecaille_efficacite : 0;
|
||||
|
||||
return {
|
||||
name: arme.name + (main ? ' ' + main : ''),
|
||||
action: 'attaque',
|
||||
initOnly: false,
|
||||
arme: arme,
|
||||
comp: comp,
|
||||
main: main,
|
||||
carac: { key: caracCode, value: caracValue },
|
||||
equipe: arme.system.equipe,
|
||||
dommagesArme: dommagesArme,
|
||||
initiative: RdDInitiative.calculInitiative(niveau, caracValue, ajustement)
|
||||
const comp = this.getCompetence(RdDActor.$getCompetenceAction(arme, main))
|
||||
const unique = [comp.id, arme.name, dommagesArme, forceRequise, ecaillesEfficacite].join('|');
|
||||
if (uniques.includes(unique)) {
|
||||
return
|
||||
}
|
||||
uniques.push(unique);
|
||||
|
||||
const caracCode = RdDActor.$getCaracAction(comp, main)
|
||||
const caracValue = this.system.carac[caracCode].value
|
||||
|
||||
const niveau = comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(main) ? -8 : -6)
|
||||
const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + ecaillesEfficacite
|
||||
|
||||
actions.push({
|
||||
name: arme.name + (main ? ' ' + main : ''),
|
||||
action: 'attaque',
|
||||
initOnly: false,
|
||||
arme: arme,
|
||||
comp: comp,
|
||||
main: main,
|
||||
carac: { key: caracCode, value: caracValue },
|
||||
equipe: arme.system.equipe,
|
||||
dommagesArme: dommagesArme,
|
||||
forceRequise: forceRequise,
|
||||
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) {
|
||||
@@ -239,10 +238,10 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
static $getCompetenceAction(arme, main) {
|
||||
switch (main) {
|
||||
case '(1 main)': return arme.competence1Mains()
|
||||
case '(2 mains)': return arme.competence2Mains()
|
||||
case '(lancer)': return arme.system.lancer
|
||||
case '(tir)': return arme.system.tir
|
||||
case ATTAQUE_TYPE.UNE_MAIN: return arme.competence1Mains()
|
||||
case ATTAQUE_TYPE.DEUX_MAINS: return arme.competence2Mains()
|
||||
case ATTAQUE_TYPE.LANCER: return arme.system.lancer
|
||||
case ATTAQUE_TYPE.TIR: return arme.system.tir
|
||||
default: return arme.system.competence
|
||||
}
|
||||
}
|
||||
@@ -507,7 +506,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
'system.sante.fatigue.value': 0,
|
||||
'system.compteurs.ethylisme': { value: 1, nb_doses: 0, jet_moral: false }
|
||||
})
|
||||
await this.removeEffects(e => e.id != STATUSES.StatusDemiReve);
|
||||
await this.removeEffects(e => !e.statuses?.has(STATUSES.StatusDemiReve));
|
||||
await this.supprimerBlessures(it => true);
|
||||
await ChatMessage.create({
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
@@ -2278,13 +2277,12 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
static _getComposantsCaracDerivee(caracName) {
|
||||
switch (Grammar.toLowerCaseNoAccent(caracName)) {
|
||||
case 'reve-actuel': case 'reve actuel': return ['reve']
|
||||
case 'chance-actuelle': case 'chance actuelle': return ['chance']
|
||||
case 'vie': return ['constitution']
|
||||
case 'tir': return ['vue', 'dexterite']
|
||||
case 'lancer': return ['force', 'dexterite', 'vue']
|
||||
case 'melee': return ['force', 'agilite']
|
||||
case 'derobee': return ['agilite']
|
||||
case CARACS.REVE_ACTUEL: case 'reve actuel': return [CARACS.REVE]
|
||||
case CARACS.CHANCE_ACTUELLE: case 'chance actuelle': return [CARACS.CHANCE]
|
||||
case CARACS.TIR: return [CARACS.DEXTERITE, CARACS.VUE]
|
||||
case CARACS.LANCER: return [CARACS.FORCE, CARACS.DEXTERITE, CARACS.VUE]
|
||||
case CARACS.MELEE: return [CARACS.FORCE, CARACS.AGILITE]
|
||||
case CARACS.DEROBEE: return [CARACS.AGILITE]
|
||||
}
|
||||
return []
|
||||
}
|
||||
@@ -2515,29 +2513,27 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async computeArmure(attackerRoll) {
|
||||
let dmg = (attackerRoll.dmg.dmgArme ?? 0) + (attackerRoll.dmg.dmgActor ?? 0);
|
||||
let armeData = attackerRoll.arme;
|
||||
async computeArmure(dmg) {
|
||||
let baseDmg = (dmg.dmgArme ?? 0) + (dmg.dmgActor ?? 0);
|
||||
let protection = 0;
|
||||
const armures = this.items.filter(it => it.type == "armure" && it.system.equipe);
|
||||
for (const armure of armures) {
|
||||
protection += await RdDDice.rollTotal(armure.system.protection.toString());
|
||||
if (dmg > 0 && attackerRoll.dmg.encaisserSpecial != "noarmure") {
|
||||
await armure.deteriorerArmure(dmg)
|
||||
dmg = 0;
|
||||
if (dmg.encaisserSpecial != "noarmure") {
|
||||
const armures = this.items.filter(it => it.type == "armure" && it.system.equipe)
|
||||
|
||||
for (const armure of armures) {
|
||||
protection += await RdDDice.rollTotal(armure.system.protection.toString());
|
||||
if (baseDmg > 0 && dmg.encaisserSpecial != "noarmure") {
|
||||
await armure.deteriorerArmure(baseDmg)
|
||||
baseDmg = 0;
|
||||
}
|
||||
}
|
||||
protection -= Math.min(dmg.penetration, protection)
|
||||
protection += this.getProtectionNaturelle();
|
||||
// Gestion des cas particuliers sur la fenêtre d'encaissement
|
||||
if (dmg.encaisserSpecial == "chute") {
|
||||
protection = Math.min(protection, 2);
|
||||
}
|
||||
}
|
||||
const penetration = Misc.toInt(armeData?.system.penetration ?? 0);
|
||||
protection = Math.max(protection - penetration, 0);
|
||||
protection += this.getProtectionNaturelle();
|
||||
// Gestion des cas particuliers sur la fenêtre d'encaissement
|
||||
if (attackerRoll.dmg.encaisserSpecial == "noarmure") {
|
||||
protection = 0;
|
||||
}
|
||||
if (attackerRoll.dmg.encaisserSpecial == "chute") {
|
||||
protection = Math.min(protection, 2);
|
||||
}
|
||||
console.log("Final protect", protection, attackerRoll);
|
||||
console.log("Final protect", protection, dmg)
|
||||
return protection;
|
||||
}
|
||||
|
||||
@@ -3051,15 +3047,15 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _rollArtV2(oeuvreId, callbackAction = async (actor, rd) => await actor._resultArtV2(rd)) {
|
||||
async _rollArtV2(oeuvreId) {
|
||||
const oeuvre = this.items.get(oeuvreId)
|
||||
const rollData = {
|
||||
title: `Interpretation de ${oeuvre.name} par ${this.name}`,
|
||||
mode: {
|
||||
allowed: ["oeuvre"]
|
||||
type: {
|
||||
allowed: ["oeuvre"],
|
||||
current: "oeuvre",
|
||||
},
|
||||
selected: {
|
||||
mode: "oeuvre",
|
||||
oeuvre: { key: oeuvre.id },
|
||||
},
|
||||
ids: {
|
||||
@@ -3067,24 +3063,14 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
}
|
||||
await RollDialog.create(rollData, {
|
||||
onRoll: (dialog) => {
|
||||
this._onCloseRollDialog(),
|
||||
onRollDone: (dialog) => {
|
||||
if (!OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST))
|
||||
dialog.close()
|
||||
},
|
||||
customChatMessage: true,
|
||||
callbacks: [callbackAction]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async _resultArtV2(artData) {
|
||||
const niveau = artData.oeuvre.system.niveau ?? 0;
|
||||
const baseQualite = (artData.rolled.isSuccess ? niveau : artData.competence.system.niveau);
|
||||
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite;
|
||||
|
||||
await RdDRollResult.displayRollData(artData, this.name, `chat-resultat-${artData.art}.hbs`);
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
|
||||
async rollOeuvre(id) {
|
||||
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
|
||||
return await this._rollArtV2(id)
|
||||
@@ -3170,7 +3156,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
async _resultArt(artData) {
|
||||
const niveau = artData.oeuvre.system.niveau ?? 0;
|
||||
const baseQualite = (artData.rolled.isSuccess ? niveau : artData.competence.system.niveau);
|
||||
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite;
|
||||
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite
|
||||
|
||||
await RdDRollResult.displayRollData(artData, this.name, `chat-resultat-${artData.art}.hbs`);
|
||||
}
|
||||
@@ -3191,7 +3177,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
async _resultRecetteCuisine(cuisine) {
|
||||
const niveauRecette = cuisine.oeuvre.system.niveau ?? 0;
|
||||
const baseQualite = (cuisine.rolled.isSuccess ? niveauRecette : cuisine.competence.system.niveau);
|
||||
cuisine.qualiteFinale = Math.min(baseQualite, niveauRecette) + cuisine.rolled.ptQualite;
|
||||
cuisine.qualiteFinale = Math.min(baseQualite, niveauRecette) + cuisine.rolled.ptQualite
|
||||
cuisine.exotismeFinal = Math.min(Math.min(cuisine.qualiteFinale, cuisine.oeuvre.system.exotisme ?? 0), 0);
|
||||
cuisine.sust = cuisine.oeuvre.system.sust * Math.min(cuisine.proportions, cuisine.proportionsMax ?? cuisine.proportions)
|
||||
const platCuisine = {
|
||||
@@ -3249,3 +3235,4 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -14,9 +14,8 @@ import { RdDConfirm } from "../rdd-confirm.js";
|
||||
import { RdDCarac } from "../rdd-carac.js";
|
||||
import { RdDRollResult } from "../rdd-roll-result.js";
|
||||
|
||||
import { RdDItemCompetence } from "../item-competence.js";
|
||||
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
|
||||
import { RdDItemArme } from "../item/arme.js";
|
||||
import { RdDItemCompetence } from "../item-competence.js";
|
||||
|
||||
import { ChatUtility } from "../chat-utility.js";
|
||||
import { DialogValidationEncaissement } from "../dialog-validation-encaissement.js";
|
||||
@@ -25,6 +24,7 @@ import { RdDEmpoignade } from "../rdd-empoignade.js";
|
||||
import { RdDPossession } from "../rdd-possession.js";
|
||||
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, POSSESSION_SANS_DRACONIC } from "../item/base-items.js";
|
||||
import { RollDataAjustements } from "../rolldata-ajustements.js";
|
||||
import { MappingCreatureArme } from "../item/mapping-creature-arme.mjs";
|
||||
|
||||
/**
|
||||
* Classe de base pour les acteurs disposant de rêve (donc, pas des objets)
|
||||
@@ -80,7 +80,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
getBonusDegat() { return RdDCarac.getCaracDerivee(this.getEncombrementMax()).plusdom }
|
||||
|
||||
getMoralTotal() { return 0 }
|
||||
listeAmoureux() {return []}
|
||||
listeAmoureux() { return [] }
|
||||
getProtectionNaturelle() { return Number(this.system.attributs?.protection?.value ?? 0) }
|
||||
getSConst() { return 0 }
|
||||
|
||||
@@ -113,13 +113,12 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
|
||||
listActions({ isAttaque = false, isEquipe = false }) {
|
||||
return this.itemTypes[ITEM_TYPES.competencecreature]
|
||||
.filter(it => RdDItemCompetenceCreature.isAttaque(it))
|
||||
.map(it => RdDItemCompetenceCreature.attaqueCreature(it))
|
||||
.filter(it => it.isAttaque())
|
||||
.map(it => it.attaqueCreature())
|
||||
.filter(it => it != undefined);
|
||||
}
|
||||
|
||||
|
||||
async computeArmure(attackerRoll) { return this.getProtectionNaturelle() }
|
||||
async computeArmure(dmg) { return this.getProtectionNaturelle() }
|
||||
async remiseANeuf() { }
|
||||
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { }
|
||||
|
||||
@@ -191,6 +190,10 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
return RdDItemArme.getArme(armeParadeId ? this.getEmbeddedDocument('Item', armeParadeId) : undefined)
|
||||
}
|
||||
|
||||
isForceInsuffisante(forceRequise) {
|
||||
return false
|
||||
}
|
||||
|
||||
getDraconicOuPossession() { return POSSESSION_SANS_DRACONIC }
|
||||
|
||||
getPossession(possessionId) {
|
||||
@@ -222,8 +225,13 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
/* -------------------------------------------- */
|
||||
isEffectAllowed(effectId) { return false }
|
||||
|
||||
getEffects(filter = e => true) {
|
||||
return this.getEmbeddedCollection("ActiveEffect").filter(filter);
|
||||
getEffects(filter = e => true, forceRequise = undefined) {
|
||||
const effects = this.getEmbeddedCollection("ActiveEffect")
|
||||
const selected = effects.filter(filter)
|
||||
if (forceRequise && this.isForceInsuffisante(forceRequise)) {
|
||||
selected.push(StatusEffects.prepareActiveEffect(STATUSES.StatusForceWeak))
|
||||
}
|
||||
return selected
|
||||
}
|
||||
|
||||
getEffectByStatus(statusId) {
|
||||
@@ -248,7 +256,8 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
|
||||
async removeEffects(filter = e => true) {
|
||||
if (game.user.isGM) {
|
||||
const ids = this.getEffects(filter).map(it => it.id);
|
||||
const effectsToRemove = this.getEffects(filter);
|
||||
const ids = effectsToRemove.map(it => it.id);
|
||||
await this.deleteEmbeddedDocuments('ActiveEffect', ids);
|
||||
}
|
||||
}
|
||||
@@ -259,11 +268,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
}
|
||||
|
||||
getSurprise(isCombat = undefined) {
|
||||
return StatusEffects.typeSurprise(
|
||||
this.getEffects()
|
||||
.map(it => StatusEffects.niveauSurprise(it, isCombat))
|
||||
.reduce(Misc.sum(), 0)
|
||||
)
|
||||
return StatusEffects.getSurprise(this.getEffects(), isCombat)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -412,7 +417,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
}
|
||||
if (competence.type == ITEM_TYPES.competencecreature) {
|
||||
const token = RdDUtility.getSelectedToken(this)
|
||||
const arme = RdDItemCompetenceCreature.armeCreature(competence)
|
||||
const arme = MappingCreatureArme.armeCreature(competence)
|
||||
if (arme && options.tryTarget && Targets.hasTargets()) {
|
||||
Targets.selectOneTargetToken(target => {
|
||||
if (arme.action == "possession") {
|
||||
@@ -425,7 +430,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
return;
|
||||
}
|
||||
// Transformer la competence de créature
|
||||
RdDItemCompetenceCreature.setRollDataCreature(rollData)
|
||||
MappingCreatureArme.setRollDataCreature(rollData)
|
||||
}
|
||||
const dialogLabel = 'Jet ' + Grammar.apostrophe('de', competence.name);
|
||||
await this.openRollDialog({
|
||||
@@ -447,13 +452,13 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
/** --------------------------------------------
|
||||
* @param {*} arme item d'arme/compétence de créature
|
||||
* @param {*} categorieArme catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
rollArme(arme, categorieArme = 'competence', token = undefined) {
|
||||
token = token ?? RdDUtility.getSelectedToken(this)
|
||||
const compToUse = RdDItemArme.getCompetenceArme(arme, categorieArme)
|
||||
if (!RdDItemArme.isUtilisable(arme)) {
|
||||
ui.notifications.warn(`Arme inutilisable: ${arme.name} a une résistance de 0 ou moins`)
|
||||
ui.notifications.warn(`Arme inutilisable: ${arme.name} non équipée ou avec une résistance de 0 ou moins`)
|
||||
return
|
||||
}
|
||||
if (!Targets.hasTargets()) {
|
||||
@@ -490,29 +495,37 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
/* -------------------------------------------- */
|
||||
async encaisser() { await RdDEncaisser.encaisser(this) }
|
||||
|
||||
async encaisserDommages(rollData, attacker = undefined, show = undefined, attackerToken = undefined, defenderToken = undefined) {
|
||||
async encaisserDommages(dmg, attacker = undefined, show = undefined, attackerToken = undefined, defenderToken = undefined) {
|
||||
if (attacker && !await attacker.accorder(this, 'avant-encaissement')) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
const armure = await this.computeArmure(rollData);
|
||||
if (!Misc.isOwnerPlayer(this)) {
|
||||
return RdDBaseActor.remoteActorCall({
|
||||
tokenId: attackerToken?.id ?? this.token?.id,
|
||||
actorId: this.id,
|
||||
method: 'encaisserDommages', args: [dmg, attacker, show, attackerToken, defenderToken]
|
||||
})
|
||||
}
|
||||
|
||||
const armure = await this.computeArmure(dmg)
|
||||
if (ReglesOptionnelles.isUsing('validation-encaissement-gr')) {
|
||||
await this.encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken);
|
||||
await this.encaisserDommagesValidationGR(dmg, armure, show, attackerToken, defenderToken);
|
||||
}
|
||||
else {
|
||||
const jet = await RdDUtility.jetEncaissement(this, rollData, armure, { showDice: SHOW_DICE });
|
||||
const jet = await RdDUtility.jetEncaissement(this, dmg, armure, { showDice: SHOW_DICE });
|
||||
await this.$onEncaissement(jet, show, attackerToken, defenderToken)
|
||||
}
|
||||
}
|
||||
|
||||
async encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken) {
|
||||
async encaisserDommagesValidationGR(dmg, armure, show, attackerToken, defenderToken) {
|
||||
if (!game.user.isGM) {
|
||||
RdDBaseActor.remoteActorCall({
|
||||
tokenId: this.token?.id,
|
||||
actorId: this.id,
|
||||
method: 'encaisserDommagesValidationGR', args: [rollData, armure, show, attackerToken, defenderToken]
|
||||
method: 'encaisserDommagesValidationGR', args: [dmg, armure, show, attackerToken, defenderToken]
|
||||
})
|
||||
} else {
|
||||
DialogValidationEncaissement.validerEncaissement(this, rollData, armure,
|
||||
DialogValidationEncaissement.validerEncaissement(this, dmg, armure,
|
||||
jet => this.$onEncaissement(jet, show, attackerToken, defenderToken));
|
||||
}
|
||||
}
|
||||
@@ -549,15 +562,37 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
}
|
||||
}
|
||||
|
||||
async encaisserRecul(force, dmgArme = 0) {
|
||||
const diffRecul = this.getTaille() - force - dmgArme
|
||||
const rolled = await RdDResolutionTable.roll(10, diffRecul)
|
||||
if (rolled.isSuccess) {
|
||||
return 'encaisse'
|
||||
}
|
||||
if (rolled.isETotal || (await this.rollEquilibre(diffRecul)).isEchec) {
|
||||
await this.setEffect(STATUSES.StatusProne, true)
|
||||
return 'chute'
|
||||
}
|
||||
return 'recul'
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollEquilibre(diff) {
|
||||
// TODO: accrobatie optionnelle sur jet d'équilibre?
|
||||
if (ReglesOptionnelles.isSet('acrobatie-pour-recul')) {
|
||||
diff += Math.max(0, this.getCompetence('acrobatie')?.system.niveau ?? 0)
|
||||
}
|
||||
return await RdDResolutionTable.roll(this.getAgilite(), diff);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async accorder(entite, when = 'avant-encaissement') {
|
||||
if (when != game.settings.get(SYSTEM_RDD, "accorder-entite-cauchemar")
|
||||
|| entite == undefined
|
||||
|| !entite.isEntite([ENTITE_INCARNE])
|
||||
|| entite.isEntiteAccordee(this)) {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
const rolled = await RdDResolutionTable.roll(this.getReveActuel(), - Number(entite.getNiveau()));
|
||||
const rolled = await RdDResolutionTable.roll(this.getReveActuel(), - Number(entite.getNiveau()))
|
||||
const rollData = {
|
||||
alias: this.getAlias(),
|
||||
rolled: rolled,
|
||||
@@ -566,11 +601,11 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
};
|
||||
|
||||
if (rolled.isSuccess) {
|
||||
await entite.setEntiteReveAccordee(this);
|
||||
await entite.setEntiteReveAccordee(this)
|
||||
}
|
||||
|
||||
await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-accorder-cauchemar.hbs');
|
||||
await this.appliquerAjoutExperience(rollData, true);
|
||||
await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-accorder-cauchemar.hbs')
|
||||
await this.appliquerAjoutExperience(rollData, true)
|
||||
return rolled.isSuccess;
|
||||
}
|
||||
|
||||
|
@@ -5,9 +5,9 @@ import { RdDSheetUtility } from "../rdd-sheet-utility.js";
|
||||
import { Monnaie } from "../item-monnaie.js";
|
||||
import { ITEM_TYPES } from "../constants.js";
|
||||
import { RdDItem } from "../item.js";
|
||||
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
|
||||
import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js";
|
||||
import { ItemAction } from "../item/item-actions.js";
|
||||
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/**
|
||||
@@ -56,7 +56,10 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
this._appliquerRechercheObjets(formData.conteneurs, formData.inventaires);
|
||||
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
|
||||
formData.competences.filter(it => it.type == ITEM_TYPES.competencecreature)
|
||||
.forEach(it => it.isdommages = RdDItemCompetenceCreature.isDommages(it))
|
||||
.forEach(it => {
|
||||
const competenceCreature = new RdDItemCompetenceCreature(it.toObject(), { parent: it.parent });
|
||||
it.isdommages = competenceCreature.isDommages();
|
||||
})
|
||||
|
||||
return formData;
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import { RdDAudio } from "../rdd-audio.js";
|
||||
import { RdDConfirm } from "../rdd-confirm.js";
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
import { SystemCompendiums } from "../settings/system-compendiums.js";
|
||||
import { RdDItem } from "../item.js";
|
||||
|
||||
export class RdDBaseActor extends Actor {
|
||||
|
||||
@@ -499,7 +500,8 @@ export class RdDBaseActor extends Actor {
|
||||
/* -------------------------------------------- */
|
||||
async computeEncTotal() {
|
||||
if (!this.pack) {
|
||||
this.encTotal = this.items.map(it => it.getEncTotal()).reduce(Misc.sum(), 0);
|
||||
this.encTotal = this.items.filter(it => RdDItem.getItemTypesInventaire().includes(it.type))
|
||||
.map(it => it.getEncTotal()).reduce(Misc.sum(), 0)
|
||||
return this.encTotal;
|
||||
}
|
||||
return 0;
|
||||
@@ -758,10 +760,10 @@ export class RdDBaseActor extends Actor {
|
||||
getCaracInit(competence) { return 0 }
|
||||
|
||||
listAttaques() {
|
||||
return this.listActions({ isAttaque: true, isEquipe:false })
|
||||
return this.listActions({ isAttaque: true, isEquipe: false })
|
||||
}
|
||||
|
||||
listActions({ isAttaque = false, isEquipe=false }) { return [] }
|
||||
listActions({ isAttaque = false, isEquipe = false }) { return [] }
|
||||
|
||||
listActionsPossessions() {
|
||||
return this.itemTypes[ITEM_TYPES.possession]
|
||||
|
@@ -1,6 +1,4 @@
|
||||
import { Grammar } from "../grammar.js";
|
||||
import { ITEM_TYPES } from "../constants.js";
|
||||
import { LIST_CARAC_AUTRES } from "../rdd-carac.js";
|
||||
import { RdDBaseActorSang } from "./base-actor-sang.js";
|
||||
|
||||
export class RdDCreature extends RdDBaseActorSang {
|
||||
@@ -45,5 +43,4 @@ export class RdDCreature extends RdDBaseActorSang {
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ import { SYSTEM_RDD } from "../../constants.js";
|
||||
import { Misc } from "../../misc.js";
|
||||
import { EXPORT_CSV_SCRIPTARIUM, OptionsAvancees } from "../../settings/options-avancees.js";
|
||||
import { ExportScriptarium } from "./export-scriptarium.js";
|
||||
import { CATEGORIES_COMPETENCES, CATEGORIES_DRACONIC, Mapping } from "./mapping.js";
|
||||
import { CATEGORIES_COMPETENCES_BASE, CATEGORIES_DRACONIC, Mapping } from "./mapping.js";
|
||||
|
||||
export class RdDActorExportSheet extends RdDActorSheet {
|
||||
static init() {
|
||||
@@ -44,7 +44,7 @@ export class RdDActorExportSheet extends RdDActorSheet {
|
||||
formData.context = Mapping.prepareContext(this.actor)
|
||||
formData.attaques = this.actor.listActionsAttaque()
|
||||
formData.export = this.getMappingValues(formData.context, this.actor)
|
||||
formData.competences = this.getCompetences(CATEGORIES_COMPETENCES)
|
||||
formData.competences = this.getCompetences(CATEGORIES_COMPETENCES_BASE)
|
||||
formData.draconic = this.getCompetences(CATEGORIES_DRACONIC)
|
||||
const legeres = this.actor.nbBlessuresLegeres()
|
||||
const graves = this.actor.nbBlessuresGraves()
|
||||
|
@@ -9,7 +9,7 @@ import { RdDBonus } from "../../rdd-bonus.js"
|
||||
import { TMRType } from "../../tmr-utility.js"
|
||||
|
||||
|
||||
export const CATEGORIES_COMPETENCES = [
|
||||
export const CATEGORIES_COMPETENCES_BASE = [
|
||||
"generale",
|
||||
"particuliere",
|
||||
"specialisee",
|
||||
@@ -88,7 +88,7 @@ const MAPPING_BASE = [
|
||||
{ column: "endurance_actuel", rollClass: 'jet-endurance', getter: (actor, context) => actor.system.sante.endurance.value },
|
||||
{ column: "esquive", getter: (actor, context) => Mapping.getEsquive(context) },
|
||||
{ column: "esquive_armure", getter: (actor, context) => Mapping.getEsquiveArmure(context) },
|
||||
{ column: "competences", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_COMPETENCES) },
|
||||
{ column: "competences", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_COMPETENCES_BASE) },
|
||||
{ column: "draconic", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_DRACONIC) },
|
||||
]
|
||||
|
||||
|
@@ -197,8 +197,12 @@ export class ChatUtility {
|
||||
|
||||
static async onCreateChatMessage(chatMessage, options, id) {
|
||||
if (chatMessage.isAuthor) {
|
||||
await chatMessage.setFlag(SYSTEM_RDD, 'rdd-timestamp', game.system.rdd.calendrier.getTimestamp());
|
||||
await ChatUtility.setTimestamp(chatMessage)
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
@@ -106,3 +106,14 @@ export const ITEM_TYPES = {
|
||||
nombreastral: 'nombreastral',
|
||||
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" }
|
||||
}
|
||||
|
@@ -7,18 +7,17 @@ import { RdDUtility } from "./rdd-utility.js";
|
||||
*/
|
||||
export class DialogValidationEncaissement extends Dialog {
|
||||
|
||||
static async validerEncaissement(actor, rollData, armure, onEncaisser) {
|
||||
const encaissement = await RdDUtility.jetEncaissement(actor, rollData, armure, { showDice: HIDE_DICE });
|
||||
static async validerEncaissement(actor, dmg, armure, onEncaisser) {
|
||||
const encaissement = await RdDUtility.jetEncaissement(actor, dmg, armure, { showDice: HIDE_DICE });
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-validation-encaissement.hbs', {
|
||||
actor: actor,
|
||||
rollData: rollData,
|
||||
encaissement: encaissement
|
||||
});
|
||||
new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, onEncaisser).render(true);
|
||||
new DialogValidationEncaissement(html, actor, dmg, armure, encaissement, onEncaisser).render(true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(html, actor, rollData, armure, encaissement, onEncaisser) {
|
||||
constructor(html, actor, dmg, armure, encaissement, onEncaisser) {
|
||||
// Common conf
|
||||
let buttons = {
|
||||
"valider": { label: "Valider", callback: html => this.onValider() },
|
||||
@@ -42,11 +41,11 @@ export class DialogValidationEncaissement extends Dialog {
|
||||
super(dialogConf, dialogOptions);
|
||||
|
||||
this.actor = actor
|
||||
this.rollData = rollData;
|
||||
this.armure = armure;
|
||||
this.encaissement = encaissement;
|
||||
this.onEncaisser = onEncaisser;
|
||||
this.forceDiceResult = {total: encaissement.roll.result };
|
||||
this.dmg = dmg
|
||||
this.armure = armure
|
||||
this.encaissement = encaissement
|
||||
this.onEncaisser = onEncaisser
|
||||
this.forceDiceResult = {total: encaissement.roll.result }
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -55,14 +54,14 @@ export class DialogValidationEncaissement extends Dialog {
|
||||
this.html = html;
|
||||
this.html.find('input.encaissement-roll-result').keyup(async event => {
|
||||
this.forceDiceResult.total = event.currentTarget.value;
|
||||
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
|
||||
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.dmg, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
|
||||
this.html.find('label.encaissement-total').text(this.encaissement.total);
|
||||
this.html.find('label.encaissement-blessure').text(this.encaissement.blessures)
|
||||
});
|
||||
}
|
||||
|
||||
async onValider() {
|
||||
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
|
||||
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.dmg, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
|
||||
this.onEncaisser(this.encaissement)
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { RdDItem } from "./item.js";
|
||||
import { SANS_COMPETENCE } from "./item/base-items.js";
|
||||
import { CATEGORIES_COMPETENCES, SANS_COMPETENCE } from "./item/base-items.js";
|
||||
import { Misc } from "./misc.js";
|
||||
|
||||
const competenceTroncs = [["Esquive", "Dague", "Corps à corps"],
|
||||
@@ -25,16 +26,6 @@ const limitesArchetypes = [
|
||||
];
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export const CATEGORIES_COMPETENCES = {
|
||||
"generale": { base: -4, label: "Générales" },
|
||||
"particuliere": { base: -8, label: "Particulières" },
|
||||
"specialisee": { base: -11, label: "Spécialisées" },
|
||||
"connaissance": { base: -11, label: "Connaissances" },
|
||||
"draconic": { base: -11, label: "Draconic" },
|
||||
"melee": { base: -6, label: "Mêlée" },
|
||||
"tir": { base: -8, label: "Tir" },
|
||||
"lancer": { base: -8, label: "Lancer" }
|
||||
}
|
||||
|
||||
function _buildCumulXP() {
|
||||
let cumulXP = { "-11": 0 };
|
||||
@@ -49,7 +40,12 @@ function _buildCumulXP() {
|
||||
|
||||
const competence_xp_cumul = _buildCumulXP();
|
||||
|
||||
export class RdDItemCompetence extends Item {
|
||||
export class RdDItemCompetence extends RdDItem {
|
||||
|
||||
static get ITEM_TYPE() { return ITEM_TYPES.competence }
|
||||
|
||||
static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp" }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getLabelCategorie(category) {
|
||||
return CATEGORIES_COMPETENCES[category].label;
|
||||
|
@@ -1,87 +1,49 @@
|
||||
|
||||
import { ITEM_TYPES } from "./constants.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { RdDInitiative } from "./initiative.mjs";
|
||||
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" },
|
||||
}
|
||||
import { RdDInitiative } from "./initiative.mjs";
|
||||
import { RdDItemArme } from "./item/arme.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDItemCompetenceCreature extends Item {
|
||||
export class RdDItemCompetenceCreature extends RdDItem {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
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 ITEM_TYPE() { return ITEM_TYPES.competencecreature }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static armeCreature(item) {
|
||||
const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(item)
|
||||
static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp" }
|
||||
|
||||
isParade() { return this.system.iscombat && (this.system.categorie_parade ?? '') != '' }
|
||||
isBouclier() { return this.system.categorie_parade.includes('bouclier') }
|
||||
|
||||
attaqueCreature() {
|
||||
const categorieAttaque = this.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;
|
||||
}
|
||||
static attaqueCreature(comp) {
|
||||
const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(comp)
|
||||
if (categorieAttaque != undefined) {
|
||||
const initative = RdDInitiative.calculInitiative(comp.system.niveau, comp.system.carac_value);
|
||||
const armeComp = new RdDItem({
|
||||
name: comp.name,
|
||||
type: ITEM_TYPES.arme,
|
||||
img: comp.img,
|
||||
system: {
|
||||
competence: comp.name,
|
||||
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
|
||||
niveau: comp.system.niveau,
|
||||
initiative: initative,
|
||||
mortalite: comp.system.mortalite,
|
||||
dommages: comp.system.dommages,
|
||||
equipe: true,
|
||||
resistance: 100,
|
||||
penetration: 0,
|
||||
force: 0,
|
||||
rapide: true,
|
||||
}
|
||||
});
|
||||
const initative = RdDInitiative.calculInitiative(this.system.niveau, this.system.carac_value);
|
||||
const attaque = {
|
||||
name: comp.name,
|
||||
action: comp.isCompetencePossession() ? 'possession' : 'attaque',
|
||||
name: this.name,
|
||||
action: this.isCompetencePossession() ? 'possession' : 'attaque',
|
||||
initOnly: false,
|
||||
arme: armeComp,
|
||||
comp: comp,
|
||||
carac: { key: comp.name, value: comp.system.carac_value },
|
||||
arme: new RdDItemArme({
|
||||
name: this.name,
|
||||
type: ITEM_TYPES.arme,
|
||||
img: this.img,
|
||||
system: {
|
||||
competence: this.name,
|
||||
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
|
||||
niveau: this.system.niveau,
|
||||
initiative: initative,
|
||||
mortalite: this.system.mortalite,
|
||||
dommages: this.system.dommages,
|
||||
equipe: true,
|
||||
resistance: 100,
|
||||
penetration: 0,
|
||||
force: 0,
|
||||
rapide: true,
|
||||
}
|
||||
}),
|
||||
comp: this,
|
||||
carac: { key: this.name, value: this.system.carac_value },
|
||||
equipe: true,
|
||||
mortalite: comp.system.mortalite,
|
||||
dmg: comp.system.dommages,
|
||||
mortalite: this.system.mortalite,
|
||||
dmg: this.system.dommages,
|
||||
initiative: initative
|
||||
};
|
||||
return attaque
|
||||
@@ -89,41 +51,28 @@ export class RdDItemCompetenceCreature extends Item {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isAttaque(item) {
|
||||
return RdDItemCompetenceCreature.getCategorieAttaque(item) != undefined
|
||||
isAttaque() {
|
||||
return this.getCategorieAttaque() != undefined
|
||||
}
|
||||
|
||||
static getCategorieAttaque(item) {
|
||||
if (item.type == ITEM_TYPES.competencecreature) {
|
||||
switch (item.system.categorie) {
|
||||
case "melee":
|
||||
case "tir":
|
||||
case "lancer":
|
||||
case "naturelle":
|
||||
case "possession":
|
||||
return item.system.categorie
|
||||
}
|
||||
getCategorieAttaque() {
|
||||
switch (this.system.categorie) {
|
||||
case "melee":
|
||||
case "tir":
|
||||
case "lancer":
|
||||
case "naturelle":
|
||||
case "possession":
|
||||
return this.system.categorie
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
static isDommages(item) {
|
||||
if (item.type == ITEM_TYPES.competencecreature) {
|
||||
switch (item.system.categorie) {
|
||||
case "melee":
|
||||
case "tir":
|
||||
case "lancer":
|
||||
case "naturelle":
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static isParade(item) {
|
||||
if (item.type == ITEM_TYPES.competencecreature) {
|
||||
return item.system.categorie_parade || item.system.isparade
|
||||
isDommages() {
|
||||
switch (this.system.categorie) {
|
||||
case "melee":
|
||||
case "tir":
|
||||
case "lancer":
|
||||
case "naturelle":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@@ -1,7 +1,9 @@
|
||||
import { ACTOR_TYPES, ITEM_TYPES } from "./constants.js";
|
||||
|
||||
import { RdDItem } from "./item.js";
|
||||
import { RdDItemCompetence } from "./item-competence.js";
|
||||
import { RdDItemSort } from "./item-sort.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { RdDItemCompetence } from "./item-competence.js";
|
||||
import { HtmlUtility } from "./html-utility.js";
|
||||
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
||||
import { SYSTEM_RDD } from "./constants.js";
|
||||
@@ -9,8 +11,6 @@ import { RdDSheetUtility } from "./rdd-sheet-utility.js";
|
||||
import { SystemCompendiums } from "./settings/system-compendiums.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
import { RdDItem } from "./item.js";
|
||||
import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js";
|
||||
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
|
||||
import { ItemAction } from "./item/item-actions.js";
|
||||
@@ -106,8 +106,8 @@ export class RdDItemSheetV1 extends foundry.appv1.sheets.ItemSheet {
|
||||
}
|
||||
|
||||
if (this.item.type == ITEM_TYPES.competencecreature) {
|
||||
formData.isparade = RdDItemCompetenceCreature.isParade(this.item)
|
||||
formData.isdommages = RdDItemCompetenceCreature.isDommages(this.item)
|
||||
formData.isparade = this.item.isParade()
|
||||
formData.isdommages = this.item.isDommages()
|
||||
}
|
||||
if (this.item.type == ITEM_TYPES.tache ||
|
||||
this.item.type == ITEM_TYPES.livre ||
|
||||
|
@@ -1,4 +1,6 @@
|
||||
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 { Misc } from "./misc.js";
|
||||
@@ -7,10 +9,6 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { SystemCompendiums } from "./settings/system-compendiums.js";
|
||||
import { RdDRaretes } from "./item/raretes.js";
|
||||
import { CATEGORIES_COMPETENCES } from "./item-competence.js";
|
||||
import { CATEGORIES_COMPETENCES_CREATURES } from "./item-competencecreature.js";
|
||||
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE } from "./item/base-items.js";
|
||||
import { ITEM_ACTIONS, DEFAULT_ACTIONS, COMMON_ACTIONS } from "./item/item-actions.js";
|
||||
|
||||
const typesInventaireMateriel = [
|
||||
ITEM_TYPES.arme,
|
||||
@@ -186,7 +184,10 @@ export class RdDItem extends Item {
|
||||
isMonnaie() { return this.type == ITEM_TYPES.monnaie; }
|
||||
isNourritureBoisson() { return this.type == ITEM_TYPES.nourritureboisson; }
|
||||
isService() { return this.type == ITEM_TYPES.service; }
|
||||
|
||||
isAttaque() { return false }
|
||||
isParade() { return false }
|
||||
isBouclier() { return false }
|
||||
getCategorieAttaque() { return undefined }
|
||||
isCompetence() { return typesObjetsCompetence.includes(this.type) }
|
||||
isEsquive() {
|
||||
return (this.isCompetence()
|
||||
|
@@ -1,10 +1,9 @@
|
||||
import { ITEM_TYPES } from "../constants.js";
|
||||
import { RdDItem } from "../item.js";
|
||||
|
||||
import { RdDItemCompetenceCreature } from "../item-competencecreature.js"
|
||||
import { BASE_CORPS_A_CORPS } from "./base-items.js";
|
||||
import { Grammar } from "../grammar.js";
|
||||
import { RdDInitiative } from "../initiative.mjs";
|
||||
import { MappingCreatureArme } from "./mapping-creature-arme.mjs";
|
||||
|
||||
const nomCategorieParade = {
|
||||
"sans-armes": "Sans arme",
|
||||
@@ -19,28 +18,49 @@ const nomCategorieParade = {
|
||||
"haches": "Haches",
|
||||
"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 {
|
||||
|
||||
static get ITEM_TYPE() { return ITEM_TYPES.arme }
|
||||
|
||||
static get defaultIcon() {
|
||||
return defaultItemImgArme
|
||||
//return "systems/foundryvtt-reve-de-dragon/icons/armes_armure/epee_sord.webp";
|
||||
}
|
||||
static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/armes_armures/epee_gnome.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) {
|
||||
switch (arme ? arme.type : '') {
|
||||
case ITEM_TYPES.arme: return arme;
|
||||
case ITEM_TYPES.competencecreature:
|
||||
return RdDItemCompetenceCreature.armeCreature(arme);
|
||||
return MappingCreatureArme.armeCreature(arme);
|
||||
}
|
||||
return RdDItemArme.corpsACorps();
|
||||
}
|
||||
@@ -51,11 +71,11 @@ export class RdDItemArme extends RdDItem {
|
||||
return arme.name
|
||||
case ITEM_TYPES.arme:
|
||||
switch (maniement) {
|
||||
case 'competence': return arme.system.competence;
|
||||
case '(1 main)': return arme.competence1Mains()
|
||||
case '(2 mains)': return arme.competence2Mains()
|
||||
case '(tir)': case 'tir': return arme.system.tir
|
||||
case '(lancer)': case 'lancer': return arme.system.lancer;
|
||||
case ATTAQUE_TYPE.COMPETENCE: return arme.system.competence;
|
||||
case ATTAQUE_TYPE.UNE_MAIN: return arme.competence1Mains()
|
||||
case ATTAQUE_TYPE.DEUX_MAINS: return arme.competence2Mains()
|
||||
case ATTAQUE_TYPE.TIR: case 'tir': return arme.system.tir
|
||||
case ATTAQUE_TYPE.LANCER: case 'lancer': return arme.system.lancer;
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
@@ -92,16 +112,13 @@ export class RdDItemArme extends RdDItem {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getCategorieParade(armeData) {
|
||||
if (![ITEM_TYPES.arme, ITEM_TYPES.competencecreature].includes(armeData.type)) {
|
||||
return ''
|
||||
}
|
||||
if (armeData.system.categorie_parade) {
|
||||
return armeData.system.categorie_parade
|
||||
}
|
||||
// pour compatibilité avec des personnages existants
|
||||
if (armeData.type == ITEM_TYPES.competencecreature || armeData.system.categorie == 'creature') {
|
||||
return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : '')
|
||||
}
|
||||
if (!armeData.type.match(/arme|competencecreature/)) {
|
||||
return ''
|
||||
}
|
||||
if (armeData.system.competence == undefined) {
|
||||
return ITEM_TYPES.competencecreature;
|
||||
}
|
||||
@@ -196,7 +213,7 @@ export class RdDItemArme extends RdDItem {
|
||||
return Number(arme.system.dommages)
|
||||
}
|
||||
const tableauDegats = arme.system.dommages.split("/");
|
||||
return Number(tableauDegats[maniement == '(1 main)' ? 0 : 1])
|
||||
return Number(tableauDegats[maniement == ATTAQUE_TYPE.UNE_MAIN ? 0 : 1])
|
||||
}
|
||||
return Number(arme.system.dommages);
|
||||
}
|
||||
@@ -205,7 +222,7 @@ export class RdDItemArme extends RdDItem {
|
||||
static armeUneOuDeuxMains(arme, aUneMain) {
|
||||
if (arme && !arme.system.cac) {
|
||||
arme = foundry.utils.duplicate(arme);
|
||||
arme.system.dommagesReels = RdDItemArme.dommagesReels(arme, aUneMain ? '(1 main)' : '(2 mains)')
|
||||
arme.system.dommagesReels = RdDItemArme.dommagesReels(arme, aUneMain ? ATTAQUE_TYPE.UNE_MAIN : ATTAQUE_TYPE.DEUX_MAINS)
|
||||
}
|
||||
return arme;
|
||||
}
|
||||
@@ -226,25 +243,10 @@ export class RdDItemArme extends RdDItem {
|
||||
return false
|
||||
}
|
||||
|
||||
static isAttaque(arme) {
|
||||
switch (arme.type) {
|
||||
case ITEM_TYPES.arme: return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0)
|
||||
case ITEM_TYPES.competencecreature: return arme.system.iscombat && RdDItemCompetenceCreature.isAttaque(item)
|
||||
}
|
||||
return false
|
||||
isAttaque() {
|
||||
return this.system.resistance > 0 || this.system.portee_courte > 0
|
||||
}
|
||||
|
||||
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) {
|
||||
let competence = actor?.getCompetenceCorpsACorps() ?? BASE_CORPS_A_CORPS
|
||||
let melee = actor ? actor.system.carac['melee'].value : 0
|
||||
|
@@ -18,3 +18,23 @@ export const SANS_COMPETENCE = {
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp"
|
||||
}
|
||||
|
||||
export const CATEGORIES_COMPETENCES = {
|
||||
"generale": { base: -4, label: "Générales" },
|
||||
"particuliere": { base: -8, label: "Particulières" },
|
||||
"specialisee": { base: -11, label: "Spécialisées" },
|
||||
"connaissance": { base: -11, label: "Connaissances" },
|
||||
"draconic": { base: -11, label: "Draconic" },
|
||||
"melee": { base: -6, label: "Mêlée" },
|
||||
"tir": { base: -8, label: "Tir" },
|
||||
"lancer": { base: -8, label: "Lancer" }
|
||||
}
|
||||
|
||||
export const CATEGORIES_COMPETENCES_CREATURES = {
|
||||
"generale": { base: 0, label: "Générale" },
|
||||
"naturelle": { base: 0, label: "Arme naturelle" },
|
||||
"melee": { base: 0, label: "Mêlée" },
|
||||
"parade": { base: 0, label: "Parade" },
|
||||
"tir": { base: 0, label: "Tir" },
|
||||
"lancer": { base: 0, label: "Lancer" },
|
||||
"possession": { base: 0, label: "Possession" },
|
||||
}
|
||||
|
42
module/item/mapping-creature-arme.mjs
Normal file
42
module/item/mapping-creature-arme.mjs
Normal file
@@ -0,0 +1,42 @@
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
@@ -34,6 +34,9 @@ export class Misc {
|
||||
return ((n % m) + m) % m;
|
||||
}
|
||||
|
||||
static inRange(value, min,max){
|
||||
return Math.max(min, Math.min(value, max))
|
||||
}
|
||||
static sum() {
|
||||
return (a, b) => Number(a) + Number(b);
|
||||
}
|
||||
|
@@ -1,4 +1,6 @@
|
||||
import { RdDItemArme } from "./item/arme.js";
|
||||
import { RdDPossession } from "./rdd-possession.js";
|
||||
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
||||
|
||||
const conditionsTactiques = [
|
||||
{ key: '', label: '', dmg: 0, attaque: 0, parade: 0, esquive: true, isTactique: false },
|
||||
@@ -12,7 +14,7 @@ const conditionsTactiques = [
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDBonus {
|
||||
static get tactiques(){
|
||||
static get tactiques() {
|
||||
return conditionsTactiques.filter(it => it.isTactique)
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
@@ -34,20 +36,47 @@ export class RdDBonus {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static dmg(rollData, actor, isEntiteIncarnee = false) {
|
||||
const diff = rollData.diffLibre;
|
||||
const dmgArme = RdDBonus.dmgArme(rollData.arme, rollData.arme?.system.dommagesReels)
|
||||
const forceRequise = rollData.arme ? RdDItemArme.valeurMain(rollData.arme.system.force ?? 0, RdDItemArme.getMainAttaque(rollData.competence)) : 0
|
||||
let dmg = {
|
||||
total: 0,
|
||||
dmgArme: dmgArme,
|
||||
diff: diff,
|
||||
dmgDiffLibre: ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(diff ?? 0) : 0,
|
||||
penetration: RdDBonus._peneration(rollData),
|
||||
dmgTactique: RdDBonus.dmgBonus(rollData.tactique),
|
||||
dmgParticuliere: RdDBonus._dmgParticuliere(rollData),
|
||||
dmgSurprise: RdDBonus.dmgBonus(rollData.ajustements?.attaqueDefenseurSurpris.used),
|
||||
mortalite: RdDBonus._calculMortalite(rollData, isEntiteIncarnee),
|
||||
dmgActor: RdDBonus.bonusDmg(actor, rollData.selectedCarac?.label.toLowerCase(), dmgArme)
|
||||
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.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere + dmg.dmgForceInsuffisante
|
||||
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) {
|
||||
@@ -93,10 +122,10 @@ export class RdDBonus {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static bonusDmg(actor, categorie, dmgArme) {
|
||||
const dmgActor = actor.getBonusDegat()
|
||||
if (categorie == undefined) {
|
||||
return 0
|
||||
}
|
||||
const dmgActor = actor.getBonusDegat()
|
||||
switch (categorie) {
|
||||
case "(tir)": case "tir": return 0
|
||||
case "(lancer)": case "lancer": return Math.max(0, Math.min(dmgArme, dmgActor));
|
||||
|
@@ -52,6 +52,15 @@ export const CARACS = {
|
||||
EMPATHIE: 'empathie',
|
||||
REVE: 'reve',
|
||||
CHANCE: 'chance',
|
||||
PROTECTION: 'protection',
|
||||
BEAUTE: 'beaute',
|
||||
PERCEPTION: 'perception',
|
||||
MELEE: 'melee',
|
||||
TIR: 'tir',
|
||||
LANCER: 'lancer',
|
||||
DEROBEE: 'derobee',
|
||||
CHANCE_ACTUELLE: 'chance-actuelle',
|
||||
REVE_ACTUEL: 'reve-actuel',
|
||||
}
|
||||
export const LIST_CARAC_PERSONNAGE = {
|
||||
[CARACS.TAILLE]: { code: CARACS.TAILLE, label: 'Taille', isCarac: true, path: 'system.carac.taille.value' },
|
||||
@@ -68,21 +77,21 @@ export const LIST_CARAC_PERSONNAGE = {
|
||||
[CARACS.EMPATHIE]: { code: CARACS.EMPATHIE, label: 'Empathie', isCarac: true, path: 'system.carac.empathie.value' },
|
||||
[CARACS.REVE]: { code: CARACS.REVE, label: 'Rêve', isCarac: true, path: 'system.carac.reve.value' },
|
||||
[CARACS.CHANCE]: { code: CARACS.CHANCE, label: 'Chance', isCarac: true, path: 'system.carac.chance.value' },
|
||||
'protection': { code: 'protection', label: 'Protection naturelle', isCarac: false, path: 'system.attributs.protection.value' },
|
||||
'beaute': { code: 'beaute', label: 'Beauté', isCarac: false, path: 'system.background.beaute.value' }
|
||||
[CARACS.PROTECTION]: { code: CARACS.PROTECTION, label: 'Protection naturelle', isCarac: false, path: 'system.attributs.protection.value' },
|
||||
[CARACS.BEAUTE]: { code: CARACS.BEAUTE, label: 'Beauté', isCarac: false, path: 'system.background.beaute.value' }
|
||||
}
|
||||
|
||||
export const LIST_CARAC_AUTRES = {
|
||||
'perception': { code: 'perception', label: 'Perception', path: 'system.carac.perception.value' },
|
||||
[CARACS.PERCEPTION]: { code: 'perception', label: 'Perception', path: 'system.carac.perception.value' },
|
||||
}
|
||||
|
||||
const LIST_CARAC_DERIVEE = {
|
||||
'melee': { code: "melee", label: 'Mêlée', path: 'system.carac.melee.value' },
|
||||
'tir': { code: "tir", label: 'Tir', path: 'system.carac.tir.value' },
|
||||
'lancer': { code: "lancer", label: 'Lancer', path: 'system.carac.lancer.value' },
|
||||
'derobee': { code: "derobee", label: 'Dérobée', path: 'system.carac.derobee.value' },
|
||||
'chance-actuelle': { code: "chance-actuelle", label: 'Chance actuelle', path: 'system.carac.lancer.value' },
|
||||
'reve-actuel': { code: "reve-actuel", label: 'Rêve actuel', path: 'system.reve.reve.value' },
|
||||
[CARACS.MELEE]: { code: CARACS.MELEE, label: 'Mêlée', path: 'system.carac.melee.value' },
|
||||
[CARACS.TIR]: { code: CARACS.TIR, label: 'Tir', path: 'system.carac.tir.value' },
|
||||
[CARACS.LANCER]: { code: CARACS.LANCER, label: 'Lancer', path: 'system.carac.lancer.value' },
|
||||
[CARACS.DEROBEE]: { code: CARACS.DEROBEE, label: 'Dérobée', path: 'system.carac.derobee.value' },
|
||||
[CARACS.CHANCE_ACTUELLE]: { code: CARACS.CHANCE_ACTUELLE, label: 'Chance actuelle', path: 'system.carac.lancer.value' },
|
||||
[CARACS.REVE_ACTUEL]: { code: CARACS.REVE_ACTUEL, label: 'Rêve actuel', path: 'system.reve.reve.value' },
|
||||
}
|
||||
|
||||
export const LIST_CARAC_ROLL = Object.values(LIST_CARAC_PERSONNAGE).filter(it => it.isCarac && it.code != 'taille')
|
||||
@@ -125,11 +134,11 @@ export class RdDCarac {
|
||||
}
|
||||
|
||||
static isIntellect(caracLabel) {
|
||||
return Grammar.toLowerCaseNoAccent(caracLabel) == 'intellect';
|
||||
return Grammar.toLowerCaseNoAccent(caracLabel) == CARACS.INTELLECT
|
||||
}
|
||||
|
||||
static isVolonte(caracLabel) {
|
||||
return Grammar.toLowerCaseNoAccent(caracLabel) == 'volonte';
|
||||
return Grammar.toLowerCaseNoAccent(caracLabel) == CARACS.VOLONTE
|
||||
}
|
||||
static isChance(caracLabel) {
|
||||
return Grammar.toLowerCaseNoAccent(caracLabel)?.match(/chance(( |-)?actuelle)?/);
|
||||
|
@@ -7,14 +7,18 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
|
||||
import { RdDRoll } from "./rdd-roll.js";
|
||||
import { RdDRollTables } from "./rdd-rolltables.js";
|
||||
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
||||
import { STATUSES } from "./settings/status-effects.js";
|
||||
import { Targets } from "./targets.js";
|
||||
import { RdDEmpoignade } from "./rdd-empoignade.js";
|
||||
import { RdDRollResult } from "./rdd-roll-result.js";
|
||||
import { RdDItemArme } from "./item/arme.js";
|
||||
import { RdDItemCompetence } from "./item-competence.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
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 = [
|
||||
@@ -368,7 +372,7 @@ export class RdDCombat {
|
||||
if (Misc.isOwnerPlayer(defender)) {
|
||||
let attackerRoll = msg.attackerRoll;
|
||||
let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : undefined;
|
||||
defender.encaisserDommages(attackerRoll, attacker, msg.attackerToken);
|
||||
defender.encaisserDommages(attackerRoll.dmg, attacker, msg.attackerToken);
|
||||
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id);
|
||||
rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
|
||||
}
|
||||
@@ -398,15 +402,19 @@ export class RdDCombat {
|
||||
/* -------------------------------------------- */
|
||||
static registerChatCallbacks(html) {
|
||||
for (let button of [
|
||||
'.parer-button',
|
||||
'.esquiver-button',
|
||||
'.button-defense',
|
||||
'.button-parade',
|
||||
'.button-esquive',
|
||||
'.button-encaisser',
|
||||
'.particuliere-attaque',
|
||||
'.encaisser-button',
|
||||
'.appel-chance-defense',
|
||||
'.appel-destinee-defense',
|
||||
'.appel-chance-attaque',
|
||||
'.appel-destinee-attaque',
|
||||
'.echec-total-attaque',
|
||||
// '.appel-chance',
|
||||
// '.chat-encaissement',
|
||||
// '.resister-recul',
|
||||
]) {
|
||||
$(html).on("click", button, event => {
|
||||
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(
|
||||
@@ -466,9 +474,11 @@ export class RdDCombat {
|
||||
|
||||
switch (button) {
|
||||
case '.particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value);
|
||||
case '.parer-button': return this.parade(attackerRoll, armeParadeId);
|
||||
case '.esquiver-button': return this.esquive(attackerRoll, compId, competence);
|
||||
case '.encaisser-button': return this.encaisser(attackerRoll, defenderRoll);
|
||||
case '.button-defense': return this.defenseV2(attackerRoll);
|
||||
|
||||
case '.button-parade': return this.parade(attackerRoll, armeParadeId);
|
||||
case '.button-esquive': return this.esquive(attackerRoll, compId, competence);
|
||||
case '.button-encaisser': return this.encaisser(attackerRoll, defenderRoll);
|
||||
case '.echec-total-attaque': return this._onEchecTotal(attackerRoll);
|
||||
|
||||
case '.appel-chance-attaque': return this.attacker.rollAppelChance(
|
||||
@@ -478,11 +488,9 @@ export class RdDCombat {
|
||||
() => this.defenseChanceuse(attackerRoll, defenderRoll),
|
||||
() => this.afficherOptionsDefense(attackerRoll, defenderRoll, { defenseChance: true }));
|
||||
case '.appel-destinee-attaque': return this.attacker.appelDestinee(
|
||||
() => this.attaqueSignificative(attackerRoll),
|
||||
() => { });
|
||||
() => this.attaqueSignificative(attackerRoll));
|
||||
case '.appel-destinee-defense': return this.defender.appelDestinee(
|
||||
() => this.defenseDestinee(defenderRoll),
|
||||
() => { });
|
||||
() => this.defenseDestinee(defenderRoll));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,27 +560,42 @@ export class RdDCombat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isEchecTotal(rollData) {
|
||||
if (!rollData.attackerRoll && rollData.ajustements.surprise.used) {
|
||||
return rollData.rolled.isEchec && rollData.rolled.code != 'notSign';
|
||||
if (rollData.ids /* roll V2*/) {
|
||||
// TODO: en cas de demi-surprise à l'attaque, tout échec est un echec total.
|
||||
// TODO: en cas de demi-surprise en défense, pas de changement à la règle de base
|
||||
return rollData.rolled.isETotal
|
||||
}
|
||||
return rollData.rolled.isETotal;
|
||||
if (rollData.mode == ROLL_TYPE_ATTAQUE && rollData.surprise == 'demi') {
|
||||
// échec normal à l'attaque en demi surprise
|
||||
return rollData.rolled.isEchec && rollData.rolled.code != 'notSign'
|
||||
}
|
||||
return rollData.rolled.isETotal
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isParticuliere(rollData) {
|
||||
if (!rollData.attackerRoll && rollData.ajustements.surprise.used) {
|
||||
return false;
|
||||
if (rollData.ids /* roll V2*/) {
|
||||
return rollData.rolled.isPart
|
||||
}
|
||||
return rollData.rolled.isPart;
|
||||
if (rollData.attackerRoll || !rollData.ajustements.surprise.used) {
|
||||
return rollData.rolled.isPart
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isReussite(rollData) {
|
||||
switch (rollData.ajustements.surprise.used) {
|
||||
case 'totale': return false;
|
||||
case 'demi': return rollData.rolled.isSign;
|
||||
if (rollData.ids /* roll V2*/) {
|
||||
return rollData.rolled.isSuccess
|
||||
}
|
||||
return rollData.rolled.isSuccess;
|
||||
if (!rollData.ajustements.surprise.used) {
|
||||
return rollData.rolled.isSuccess
|
||||
}
|
||||
switch (rollData.ajustements.surprise.used) {
|
||||
case 'totale': return false
|
||||
case 'demi': return rollData.rolled.isSign
|
||||
}
|
||||
return rollData.rolled.isSuccess
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -679,6 +702,7 @@ export class RdDCombat {
|
||||
/* -------------------------------------------- */
|
||||
_prepareAttaque(competence, arme) {
|
||||
let rollData = {
|
||||
mode: ROLL_TYPE_ATTAQUE,
|
||||
alias: this.attacker?.getAlias(),
|
||||
passeArme: foundry.utils.randomID(16),
|
||||
mortalite: arme?.system.mortalite,
|
||||
@@ -691,7 +715,7 @@ export class RdDCombat {
|
||||
};
|
||||
|
||||
if (this.attacker.isCreatureEntite()) {
|
||||
RdDItemCompetenceCreature.setRollDataCreature(rollData);
|
||||
MappingCreatureArme.setRollDataCreature(rollData);
|
||||
}
|
||||
else if (arme) {
|
||||
// Usual competence
|
||||
@@ -713,9 +737,6 @@ export class RdDCombat {
|
||||
if (RdDCombat.isReussite(attackerRoll)) {
|
||||
return await this._onAttaqueNormale(attackerRoll)
|
||||
}
|
||||
// if (RdDCombat.isParticuliere(attackerRoll) && attackerRoll.particuliere == undefined) {
|
||||
// return
|
||||
// }
|
||||
if (RdDCombat.isEchecTotal(attackerRoll)) {
|
||||
return await this._onAttaqueEchecTotal(attackerRoll)
|
||||
}
|
||||
@@ -786,8 +807,6 @@ export class RdDCombat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _sendMessageDefense(attackerRoll, defenderRoll, essaisPrecedents = undefined) {
|
||||
console.log("RdDCombat._sendMessageDefense", attackerRoll, defenderRoll, essaisPrecedents, " / ", this.attacker, this.target, this.attackerId, attackerRoll.competence.system.categorie);
|
||||
|
||||
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
|
||||
if (essaisPrecedents) {
|
||||
foundry.utils.mergeObject(attackerRoll.essais, essaisPrecedents, { overwrite: true });
|
||||
@@ -857,7 +876,7 @@ export class RdDCombat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_filterArmesParade(defender, competence, armeAttaque) {
|
||||
let defenses = defender.items.filter(it => RdDItemArme.isParade(it))
|
||||
let defenses = defender.items.filter(it => it.isParade())
|
||||
defenses = foundry.utils.duplicate(defenses)
|
||||
defenses.forEach(armeDefense => {
|
||||
// Ajout du # d'utilisation ce round
|
||||
@@ -879,6 +898,7 @@ export class RdDCombat {
|
||||
const choixEchecTotal = await ChatMessage.create({
|
||||
whisper: ChatUtility.getOwners(this.attacker),
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.hbs', {
|
||||
rolled: attackerRoll.rolled,
|
||||
attackerId: this.attackerId,
|
||||
attacker: this.attacker,
|
||||
attackerToken: this.attackerToken,
|
||||
@@ -946,9 +966,46 @@ export class RdDCombat {
|
||||
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) {
|
||||
let defenderRoll = {
|
||||
mode: ROLL_TYPE_DEFENSE,
|
||||
alias: this.defender?.getAlias(),
|
||||
passeArme: attackerRoll.passeArme,
|
||||
diffLibre: attackerRoll.diffLibre,
|
||||
@@ -965,12 +1022,52 @@ export class RdDCombat {
|
||||
};
|
||||
|
||||
if (this.defender.isCreatureEntite()) {
|
||||
RdDItemCompetenceCreature.setRollDataCreature(defenderRoll);
|
||||
MappingCreatureArme.setRollDataCreature(defenderRoll);
|
||||
}
|
||||
|
||||
return defenderRoll;
|
||||
}
|
||||
|
||||
async _onDefense(rollData) {
|
||||
const isEsquive = rollData.current[PART_DEFENSE].isEsquive
|
||||
const isParade = !isEsquive
|
||||
if (RdDCombat.isReussite(rollData)) {
|
||||
if (isParade) {
|
||||
await this.computeDeteriorationArme(rollData)
|
||||
}
|
||||
|
||||
if (RdDCombat.isParticuliere(rollData)) {
|
||||
await this._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) {
|
||||
if (RdDCombat.isReussite(defenderRoll)) {
|
||||
@@ -1042,6 +1139,7 @@ export class RdDCombat {
|
||||
/* -------------------------------------------- */
|
||||
_prepareEsquive(attackerRoll, competence) {
|
||||
let rollData = {
|
||||
mode: ROLL_TYPE_DEFENSE,
|
||||
alias: this.defender.getAlias(),
|
||||
passeArme: attackerRoll.passeArme,
|
||||
diffLibre: attackerRoll.diffLibre,
|
||||
@@ -1056,7 +1154,7 @@ export class RdDCombat {
|
||||
};
|
||||
|
||||
if (this.defender.isCreatureEntite()) {
|
||||
RdDItemCompetenceCreature.setRollDataCreature(rollData);
|
||||
MappingCreatureArme.setRollDataCreature(rollData);
|
||||
}
|
||||
return rollData;
|
||||
}
|
||||
@@ -1105,7 +1203,7 @@ export class RdDCombat {
|
||||
// Est-ce une parade normale?
|
||||
if (defenderRoll.arme && attackerRoll && !defenderRoll.rolled.isPart) {
|
||||
// Est-ce que l'attaque est une particulière en force ou une charge
|
||||
if (defenderRoll.needResist || this._isForceOuCharge(attackerRoll)) {
|
||||
if (defenderRoll.needResist || this._isForceOuCharge(attackerRoll, defenderRoll.v2)) {
|
||||
|
||||
defenderRoll.show = defenderRoll.show || {}
|
||||
|
||||
@@ -1153,7 +1251,7 @@ export class RdDCombat {
|
||||
finalLevel: Misc.toInt(defenderRoll.competence.system.niveau) - dmg,
|
||||
showDice: HIDE_DICE
|
||||
});
|
||||
defenderRoll.show.desarme = desarme.rolled.isEchec;
|
||||
defenderRoll.show.desarme = desarme.rolled.isEchec
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1161,41 +1259,19 @@ export class RdDCombat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async computeRecul(defenderRoll) { // Calcul du recul (p. 132)
|
||||
if (!ReglesOptionnelles.isUsing('recul')) {
|
||||
return
|
||||
}
|
||||
const attackerRoll = defenderRoll.attackerRoll;
|
||||
if (ReglesOptionnelles.isUsing('recul') && this._isForceOuCharge(attackerRoll)) {
|
||||
const impact = this._computeImpactRecul(attackerRoll);
|
||||
const rollRecul = await RdDResolutionTable.rollData({ caracValue: 10, finalLevel: impact });
|
||||
if (rollRecul.rolled.isSuccess) {
|
||||
defenderRoll.show.recul = 'encaisse';
|
||||
} else if (rollRecul.rolled.isETotal || this._isReculCauseChute(impact)) {
|
||||
defenderRoll.show.recul = 'chute';
|
||||
await this.defender.setEffect(STATUSES.StatusProne, true);
|
||||
}
|
||||
else {
|
||||
defenderRoll.show.recul = 'recul';
|
||||
}
|
||||
if (this._isForceOuCharge(attackerRoll, defenderRoll.v2)) {
|
||||
defenderRoll.show.recul = this.defender.encaisserRecul(this.attacker.getForce(), attackerRoll.dmg.dmgArme)
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _isReculCauseChute(impact) {
|
||||
const agilite = this.defender.getAgilite();
|
||||
const chute = await RdDResolutionTable.rollData({ caracValue: agilite, finalLevel: impact });
|
||||
return chute.rolled.isEchec;
|
||||
_isForceOuCharge(attaque, isRollV2 = false /* TODO: delete roll V1 */) {
|
||||
return attaque.particuliere == 'force' || 'charge' == (isRollV2 ? attaque.tactique?.key : attaque.tactique)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_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) {
|
||||
@@ -1205,12 +1281,16 @@ export class RdDCombat {
|
||||
this._onEchecTotal(defenderRoll);
|
||||
}
|
||||
|
||||
await this.doRollEncaissement(attackerRoll, defenderRoll);
|
||||
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
|
||||
}
|
||||
|
||||
async doRollEncaissement(attackerRoll, defenderRoll) {
|
||||
if (Misc.isOwnerPlayer(this.defender)) {
|
||||
attackerRoll.attackerId = this.attackerId;
|
||||
attackerRoll.defenderTokenId = this.defenderToken.id;
|
||||
|
||||
await this.computeRecul(defenderRoll);
|
||||
await this.defender.encaisserDommages(attackerRoll, this.attacker, defenderRoll?.show, this.attackerToken, this.defenderToken);
|
||||
await this.defender.encaisserDommages(attackerRoll.dmg, this.attacker, defenderRoll?.show, this.attackerToken, this.defenderToken);
|
||||
}
|
||||
else { // envoi à un GM: les joueurs n'ont pas le droit de modifier les personnages qu'ils ne possèdent pas
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, {
|
||||
@@ -1221,9 +1301,8 @@ export class RdDCombat {
|
||||
attackerToken: this.attackerToken,
|
||||
defenderToken: this.defenderToken
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -1255,4 +1334,5 @@ export class RdDCombat {
|
||||
alias: alias
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,10 +1,9 @@
|
||||
/* -------------------------------------------- */
|
||||
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 { ITEM_TYPES } from "./constants.js";
|
||||
import { ChatUtility } from "./chat-utility.js";
|
||||
import { RdDRollResult } from "./rdd-roll-result.js";
|
||||
import { RdDRoll } from "./rdd-roll.js";
|
||||
import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDEmpoignade {
|
||||
@@ -186,7 +185,7 @@ export class RdDEmpoignade {
|
||||
malusTaille: RdDEmpoignade.getMalusTaille(empoignade, attacker, defender)
|
||||
}
|
||||
if (attacker.isCreatureEntite()) {
|
||||
RdDItemCompetenceCreature.setRollDataCreature(rollData)
|
||||
MappingCreatureArme.setRollDataCreature(rollData)
|
||||
}
|
||||
if (empoignade.system.pointsemp >= 2) {
|
||||
if (!empoignade.system.ausol) {
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { RdDItemArme } from "./item/arme.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
import { ATTAQUE_TYPE, RdDItemArme } from "./item/arme.js";
|
||||
import { ITEM_TYPES } from "./constants.js";
|
||||
|
||||
export class RdDHotbar {
|
||||
@@ -20,10 +19,13 @@ export class RdDHotbar {
|
||||
await game.user.assignHotbarMacro(macro, slot);
|
||||
}
|
||||
|
||||
static $macroNameSuffix(armeCompetence) {
|
||||
switch (armeCompetence) {
|
||||
case '(1 main)': return ' (1 main)';
|
||||
case '(2 mains)': return ' (2 main)';
|
||||
static $macroNameSuffix(maniement) {
|
||||
switch (maniement) {
|
||||
case ATTAQUE_TYPE.UNE_MAIN:
|
||||
case ATTAQUE_TYPE.DEUX_MAINS:
|
||||
case ATTAQUE_TYPE.LANCER:
|
||||
case ATTAQUE_TYPE.TIR:
|
||||
return ' ' + maniement
|
||||
case 'tir': return ' (tir)';
|
||||
case 'lancer': return ' (lancer)';
|
||||
case 'pugilat': return ' (pugilat)';
|
||||
@@ -39,22 +41,22 @@ export class RdDHotbar {
|
||||
// Les armes peuvent avoir plusieurs usages
|
||||
if (item.system.competence != '') {
|
||||
if (item.system.unemain) {
|
||||
await this.createItemMacro(item, slot++, '(1 main)')
|
||||
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.UNE_MAIN)
|
||||
}
|
||||
if (item.system.deuxmains) {
|
||||
await this.createItemMacro(item, slot++, '(2 mains)')
|
||||
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.DEUX_MAINS)
|
||||
}
|
||||
}
|
||||
if (item.system.lancer != '') {
|
||||
await this.createItemMacro(item, slot++, 'lancer')
|
||||
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.LANCER)
|
||||
}
|
||||
if (item.system.tir != '') {
|
||||
await this.createItemMacro(item, slot++, 'lancer')
|
||||
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.TIR)
|
||||
}
|
||||
}
|
||||
return
|
||||
case ITEM_TYPES.competencecreature:
|
||||
const categorie = RdDItemCompetenceCreature.getCategorieAttaque(item) ?? 'competence';
|
||||
const categorie = item.getCategorieAttaque() ?? 'competence';
|
||||
await this.createItemMacro(item, slot, categorie)
|
||||
return
|
||||
default:
|
||||
@@ -127,7 +129,7 @@ export class RdDHotbar {
|
||||
}
|
||||
return actor.rollCompetence(item);
|
||||
case ITEM_TYPES.competencecreature:
|
||||
return item.system.iscombat && !item.system.isparade
|
||||
return item.system.iscombat
|
||||
? actor.rollArme(item, categorieArme)
|
||||
: actor.rollCompetence(item);
|
||||
|
||||
|
@@ -45,6 +45,8 @@ import * as sheets from "./applications/sheets/_module.mjs"
|
||||
import { RdDItemArme } from "./item/arme.js"
|
||||
import { RdDItemArmure } from "./item/armure.js"
|
||||
import { RdDItemBlessure } from "./item/blessure.js"
|
||||
import { RdDItemCompetence } from "./item-competence.js"
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"
|
||||
import { RdDItemGemme } from "./item/gemme.js"
|
||||
import { RdDItemMaladie } from "./item/maladie.js"
|
||||
import { RdDItemOmbre } from "./item/ombre.js"
|
||||
@@ -86,6 +88,7 @@ import { RdDCombatManager, RdDCombat } from "./rdd-combat.js"
|
||||
import { Migrations } from './migrations.js'
|
||||
|
||||
import RollDialog from "./roll/roll-dialog.mjs"
|
||||
import ChatRollResult from "./roll/chat-roll-result.mjs"
|
||||
|
||||
/**
|
||||
* RdD system
|
||||
@@ -112,6 +115,8 @@ export class SystemReveDeDragon {
|
||||
arme: RdDItemArme,
|
||||
armure: RdDItemArmure,
|
||||
blessure: RdDItemBlessure,
|
||||
competence: RdDItemCompetence,
|
||||
competencecreature: RdDItemCompetenceCreature,
|
||||
gemme: RdDItemGemme,
|
||||
maladie: RdDItemMaladie,
|
||||
ombre: RdDItemOmbre,
|
||||
@@ -292,6 +297,7 @@ export class SystemReveDeDragon {
|
||||
TMRRencontres.init()
|
||||
ExportScriptarium.init()
|
||||
RollDialog.init()
|
||||
ChatRollResult.init()
|
||||
}
|
||||
|
||||
initSettings() {
|
||||
@@ -346,18 +352,7 @@ export class SystemReveDeDragon {
|
||||
})
|
||||
}
|
||||
|
||||
static async setupAccueil() {
|
||||
let exists = game.scenes.find(j => j.name == "Accueil RdD");
|
||||
if (!exists) {
|
||||
const scenes = await SystemCompendiums.loadCompendium("foundryvtt-reve-de-dragon.scenes-rdd")
|
||||
let newDocuments = scenes.filter(i => i.name == "Accueil RdD");
|
||||
await game.scenes.documentClass.create(newDocuments);
|
||||
game.scenes.find(i => i.name == "Accueil RdD").activate();
|
||||
}
|
||||
}
|
||||
|
||||
async onReady() {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Foundry VTT Initialization */
|
||||
/* -------------------------------------------- */
|
||||
@@ -376,7 +371,8 @@ export class SystemReveDeDragon {
|
||||
StatusEffects.onReady()
|
||||
RdDDice.onReady()
|
||||
RollDialog.onReady()
|
||||
RdDStatBlockParser.parseStatBlock()
|
||||
ChatRollResult.onReady()
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Affiche/Init le calendrier */
|
||||
game.system.rdd.calendrier.display()
|
||||
@@ -389,7 +385,17 @@ export class SystemReveDeDragon {
|
||||
})
|
||||
}
|
||||
|
||||
SystemReveDeDragon.setupAccueil()
|
||||
this.setupAccueil()
|
||||
}
|
||||
|
||||
async setupAccueil() {
|
||||
let exists = game.scenes.find(j => j.name == "Accueil RdD");
|
||||
if (!exists) {
|
||||
const scenes = await SystemCompendiums.loadCompendium("foundryvtt-reve-de-dragon.scenes-rdd")
|
||||
let newDocuments = scenes.filter(i => i.name == "Accueil RdD");
|
||||
await game.scenes.documentClass.create(newDocuments);
|
||||
game.scenes.find(i => i.name == "Accueil RdD").activate();
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@@ -1,9 +1,7 @@
|
||||
import { RdDRoll } from "./rdd-roll.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
import { Targets } from "./targets.js";
|
||||
import { ITEM_TYPES } from "./constants.js";
|
||||
import { RdDRollResult } from "./rdd-roll-result.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* On part du principe qu'une entité démarre tjs
|
||||
|
@@ -157,7 +157,7 @@ export class RdDResolutionTable {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static significativeRequise(chances) {
|
||||
chances.roll = Math.floor(chances.score / 2);
|
||||
chances.roll = Math.min(chances.part + 1, chances.sign)
|
||||
foundry.utils.mergeObject(chances, reussites.find(x => x.code == 'sign'), { overwrite: true });
|
||||
}
|
||||
|
||||
@@ -184,47 +184,15 @@ export class RdDResolutionTable {
|
||||
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) {
|
||||
const reussite = reussites.find(x => x.condition(chances, roll));
|
||||
if (diviseur > 1 && reussite.code == 'norm') {
|
||||
return reussiteInsuffisante;
|
||||
const reussite = reussites.find(x => x.condition(chances, roll))
|
||||
if (diviseur > 1 && reussite.isSuccess) {
|
||||
if (chances > roll * diviseur) {
|
||||
return reussiteInsuffisante
|
||||
}
|
||||
}
|
||||
return reussite;
|
||||
return reussite
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@@ -66,12 +66,11 @@ export class RdDEncaisser extends Dialog {
|
||||
/* -------------------------------------------- */
|
||||
performEncaisser(mortalite) {
|
||||
this.actor.encaisserDommages({
|
||||
dmg: {
|
||||
total: Number(this.modifier),
|
||||
ajustement: Number(this.modifier),
|
||||
encaisserSpecial: this.encaisserSpecial,
|
||||
mortalite: mortalite
|
||||
}
|
||||
total: Number(this.modifier),
|
||||
ajustement: Number(this.modifier),
|
||||
encaisserSpecial: this.encaisserSpecial,
|
||||
mortalite: mortalite,
|
||||
penetration: 0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
|
||||
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { ACTOR_TYPES } from "./constants.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
|
||||
/**
|
||||
* Extend the base Dialog entity to select roll parameters
|
||||
|
@@ -11,7 +11,6 @@ import { RdDItem } from "./item.js";
|
||||
import { RdDPossession } from "./rdd-possession.js";
|
||||
import { RdDNameGen } from "./rdd-namegen.js";
|
||||
import { RdDConfirm } from "./rdd-confirm.js";
|
||||
import { RdDItemCompetence } from "./item-competence.js";
|
||||
import { RdDResolutionTable } from "./rdd-resolution-table.js";
|
||||
import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
import { RdDRaretes } from "./item/raretes.js";
|
||||
@@ -19,10 +18,12 @@ import { RdDEmpoignade } from "./rdd-empoignade.js";
|
||||
import { ExperienceLog } from "./actor/experience-log.js";
|
||||
import { RdDCoeur } from "./coeur/rdd-coeur.js";
|
||||
import { APP_ASTROLOGIE_REFRESH } from "./sommeil/app-astrologie.js";
|
||||
import { ITEM_TYPES, RDD_CONFIG } from "./constants.js";
|
||||
import { ITEM_TYPES, RDD_CONFIG, SYSTEM_RDD } from "./constants.js";
|
||||
import { RdDBaseActor } from "./actor/base-actor.js";
|
||||
import { RdDCarac } from "./rdd-carac.js";
|
||||
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
|
||||
|
||||
import { RdDItemCompetence } from "./item-competence.js";
|
||||
import { Monnaie } from "./item-monnaie.js";
|
||||
import { ItemAction } from "./item/item-actions.js";
|
||||
|
||||
@@ -271,6 +272,7 @@ export class RdDUtility {
|
||||
|
||||
// foundry et options
|
||||
Handlebars.registerHelper('RDD_CONFIG', path => RDD_CONFIG[path])
|
||||
Handlebars.registerHelper('settings-get', (setting) => game.settings.get(SYSTEM_RDD, setting))
|
||||
Handlebars.registerHelper('linkCompendium', (pack, id, name) => RdDUtility.linkCompendium(pack, id, name));
|
||||
Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionnelles.isUsing(option));
|
||||
|
||||
@@ -344,7 +346,7 @@ export class RdDUtility {
|
||||
Handlebars.registerHelper('rarete-getChamp', (rarete, field) => RdDRaretes.getChamp(rarete, field));
|
||||
Handlebars.registerHelper('item-action-applies', (action, item, options) => ItemAction.applies(action, item, options))
|
||||
Handlebars.registerHelper('item-action-icon', (action, item) => ItemAction.icon(action, item))
|
||||
Handlebars.registerHelper('item-name', (item) => item.nameDisplay)
|
||||
Handlebars.registerHelper('item-name', (item) => item.nameDisplay)
|
||||
|
||||
// TMRs
|
||||
Handlebars.registerHelper('caseTmr-label', coord => TMRUtility.getTMRLabel(coord));
|
||||
@@ -609,35 +611,33 @@ export class RdDUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async getLocalisation(type = 'personnage') {
|
||||
let result = await RdDDice.rollTotal("1d20");
|
||||
let txt = ""
|
||||
const loc = { result: await RdDDice.rollTotal("1d20")};
|
||||
if (type == 'personnage') {
|
||||
if (result <= 3) txt = "Jambe, genou, pied, jarret";
|
||||
else if (result <= 7) txt = "Hanche, cuisse, fesse";
|
||||
else if (result <= 9) txt = "Ventre, reins";
|
||||
else if (result <= 12) txt = "Poitrine, dos";
|
||||
else if (result <= 14) txt = "Avant-bras, main, coude";
|
||||
else if (result <= 18) txt = "Epaule, bras, omoplate";
|
||||
else if (result == 19) txt = "Tête";
|
||||
else if (result == 20) txt = "Tête (visage)";
|
||||
if (loc.result <= 3) loc.txt = "Jambe, genou, pied, jarret";
|
||||
else if (loc.result <= 7) loc.txt = "Hanche, cuisse, fesse";
|
||||
else if (loc.result <= 9) loc.txt = "Ventre, reins";
|
||||
else if (loc.result <= 12) loc.txt = "Poitrine, dos";
|
||||
else if (loc.result <= 14) loc.txt = "Avant-bras, main, coude";
|
||||
else if (loc.result <= 18) loc.txt = "Epaule, bras, omoplate";
|
||||
else if (loc.result == 19) loc.txt = "Tête";
|
||||
else if (loc.result == 20) loc.txt = "Tête (visage)";
|
||||
} else {
|
||||
if (result <= 7) txt = "Jambes/Pattes";
|
||||
else if (result <= 18) txt = "Corps";
|
||||
else if (result <= 20) txt = "Tête";
|
||||
if (loc.result <= 7) loc.txt = "Jambes/Pattes";
|
||||
else if (loc.result <= 18) loc.txt = "Corps";
|
||||
else if (loc.result <= 20) loc.txt = "Tête";
|
||||
}
|
||||
|
||||
return { result: result, label: txt };
|
||||
return loc
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async jetEncaissement(actor, rollData, armure, options = { showDice: HIDE_DICE }) {
|
||||
const diff = Math.abs(rollData.diffLibre);
|
||||
let formula = RdDUtility.formuleEncaissement(diff, options)
|
||||
static async jetEncaissement(actor, dmg, armure, options = { showDice: HIDE_DICE }) {
|
||||
const diff = Math.abs(dmg.diff)
|
||||
const formula = RdDUtility.formuleEncaissement(diff, options)
|
||||
const roll = await RdDDice.roll(formula, options);
|
||||
|
||||
RdDUtility.remplaceDeMinParDifficulte(roll, diff, options);
|
||||
|
||||
return await RdDUtility.prepareEncaissement(actor, rollData, roll, armure);
|
||||
return await RdDUtility.prepareEncaissement(actor, dmg, roll, armure);
|
||||
}
|
||||
|
||||
static remplaceDeMinParDifficulte(roll, diff, options) {
|
||||
@@ -660,7 +660,7 @@ export class RdDUtility {
|
||||
}
|
||||
}
|
||||
|
||||
static formuleEncaissement(diff, options) {
|
||||
static formuleEncaissement(diff) {
|
||||
// Chaque dé fait au minimum la difficulté libre
|
||||
if (ReglesOptionnelles.isUsing('degat-minimum-malus-libre')) {
|
||||
return `2d10min${diff}`
|
||||
@@ -669,25 +669,22 @@ export class RdDUtility {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async prepareEncaissement(actor, rollData, roll, armure) {
|
||||
// La difficulté d'ataque s'ajoute aux dégâts
|
||||
const bonusDegatsDiffLibre = ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(rollData.diffLibre ?? 0) : 0
|
||||
const jetTotal = roll.total + rollData.dmg.total - armure + bonusDegatsDiffLibre
|
||||
const encaissement = RdDUtility._selectEncaissement(jetTotal, rollData.dmg.mortalite);
|
||||
static async prepareEncaissement(actor, dmg, roll, armure) {
|
||||
const jetTotal = roll.total + dmg.total - armure
|
||||
const encaissement = RdDUtility._selectEncaissement(jetTotal, dmg.mortalite);
|
||||
const over20 = Math.max(jetTotal - 20, 0);
|
||||
encaissement.dmg = rollData.dmg
|
||||
encaissement.dmg = dmg
|
||||
if (ReglesOptionnelles.isUsing('localisation-aleatoire')) {
|
||||
encaissement.dmg.loc = rollData.dmg.loc ?? await RdDUtility.getLocalisation(actor.type)
|
||||
encaissement.dmg.loc = dmg.loc ?? await RdDUtility.getLocalisation(actor.type)
|
||||
encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps;'
|
||||
}
|
||||
else {
|
||||
encaissement.dmg.loc = { label: '' }
|
||||
}
|
||||
encaissement.dmg.bonusDegatsDiffLibre = bonusDegatsDiffLibre
|
||||
encaissement.roll = roll;
|
||||
encaissement.armure = armure;
|
||||
encaissement.penetration = rollData.arme?.system.penetration ?? 0;
|
||||
encaissement.total = jetTotal;
|
||||
encaissement.roll = roll
|
||||
encaissement.armure = armure
|
||||
encaissement.penetration = dmg.penetration
|
||||
encaissement.total = jetTotal
|
||||
encaissement.vie = await RdDUtility._evaluatePerte(encaissement.vie, over20);
|
||||
encaissement.endurance = await RdDUtility._evaluatePerte(encaissement.endurance, over20);
|
||||
return encaissement;
|
||||
|
180
module/roll/chat-roll-result.mjs
Normal file
180
module/roll/chat-roll-result.mjs
Normal file
@@ -0,0 +1,180 @@
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
@@ -1,4 +1,8 @@
|
||||
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 {
|
||||
|
||||
@@ -6,23 +10,44 @@ export class RollBasicParts {
|
||||
rollData.ids.sceneId = rollData.ids.sceneId ?? canvas.scene.id
|
||||
rollData.active = RollBasicParts.$getActor(rollData)
|
||||
rollData.opponent = RollBasicParts.$getOpponent(rollData)
|
||||
if (rollData.mode.opposed == undefined) {
|
||||
rollData.mode.opposed = rollData.opponent != null
|
||||
if (rollData.type.opposed == undefined) {
|
||||
rollData.type.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) {
|
||||
return {
|
||||
selected: {},
|
||||
mode: {
|
||||
current: rollData.mode.current
|
||||
},
|
||||
type: rollData.type,
|
||||
ids: {
|
||||
sceneId: rollData.ids.sceneId,
|
||||
actorId: rollData.active.id,
|
||||
actorTokenId: rollData.active.tokenId,
|
||||
opponentId: rollData.mode.opposed ? rollData.opponent.id : undefined,
|
||||
opponentTokenId: rollData.mode.opposed ? rollData.opponent.tokenId : undefined,
|
||||
opponentId: rollData.type.opposed ? rollData.opponent.id : undefined,
|
||||
opponentTokenId: rollData.type.opposed ? rollData.opponent.tokenId : undefined,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,14 +1,14 @@
|
||||
|
||||
export const ROLL_MODE_ATTAQUE = 'attaque'
|
||||
export const ROLL_MODE_COMP = 'comp'
|
||||
export const ROLL_MODE_DEFENSE = 'defense'
|
||||
export const ROLL_MODE_JEU = 'jeu'
|
||||
export const ROLL_MODE_MEDITATION = 'meditation'
|
||||
export const ROLL_MODE_OEUVRE = 'oeuvre'
|
||||
export const ROLL_MODE_SORT = 'sort'
|
||||
export const ROLL_MODE_TACHE = 'tache'
|
||||
export const ROLL_TYPE_ATTAQUE = 'attaque'
|
||||
export const ROLL_TYPE_COMP = 'comp'
|
||||
export const ROLL_TYPE_DEFENSE = 'defense'
|
||||
export const ROLL_TYPE_JEU = 'jeu'
|
||||
export const ROLL_TYPE_MEDITATION = 'meditation'
|
||||
export const ROLL_TYPE_OEUVRE = 'oeuvre'
|
||||
export const ROLL_TYPE_SORT = 'sort'
|
||||
export const ROLL_TYPE_TACHE = 'tache'
|
||||
|
||||
export const DIFF_MODE = {
|
||||
export const DIFF = {
|
||||
LIBRE: 'libre',
|
||||
ATTAQUE: 'attaque',
|
||||
IMPOSEE: 'imposee',
|
||||
@@ -17,12 +17,12 @@ export const DIFF_MODE = {
|
||||
AUCUN: 'aucun'
|
||||
}
|
||||
|
||||
export const DIFF_MODES = {
|
||||
[DIFF_MODE.LIBRE]: { key: DIFF_MODE.LIBRE, label: "Difficulté libre", libre: true, visible: true, max: 0 },
|
||||
[DIFF_MODE.ATTAQUE]: { key: DIFF_MODE.ATTAQUE, label: "Difficulté d'attaque", libre: true, visible: true, max: 0 },
|
||||
[DIFF_MODE.IMPOSEE]: { key: DIFF_MODE.IMPOSEE, label: "Diffficulté imposée", libre: false, visible: true, max: 0 },
|
||||
[DIFF_MODE.DEFENSE]: { key: DIFF_MODE.DEFENSE, label: "Diffficulté défense", libre: false, visible: true, max: 0 },
|
||||
[DIFF_MODE.DEFAUT]: { key: DIFF_MODE.DEFAUT, label: "Difficulté", libre: true, visible: true, max: 5 },
|
||||
[DIFF_MODE.AUCUN]: { key: DIFF_MODE.AUCUN, label: "", libre: false, visible: false, max: 0 },
|
||||
export const DIFFS = {
|
||||
[DIFF.LIBRE]: { key: DIFF.LIBRE, label: "Difficulté libre", libre: true, visible: true, max: 0 },
|
||||
[DIFF.ATTAQUE]: { key: DIFF.ATTAQUE, label: "Difficulté d'attaque", libre: true, visible: true, max: 0 },
|
||||
[DIFF.IMPOSEE]: { key: DIFF.IMPOSEE, label: "Diffficulté imposée", libre: false, visible: true, max: 0 },
|
||||
[DIFF.DEFENSE]: { key: DIFF.DEFENSE, label: "Diffficulté défense", libre: false, visible: true, max: 0 },
|
||||
[DIFF.DEFAUT]: { key: DIFF.DEFAUT, label: "Difficulté", libre: true, visible: true, max: 5 },
|
||||
[DIFF.AUCUN]: { key: DIFF.AUCUN, label: "", libre: false, visible: false, max: 0 },
|
||||
}
|
||||
|
||||
|
@@ -4,12 +4,14 @@ import { PART_COMP } from "./roll-part-comp.mjs";
|
||||
import { RdDResolutionTable } from "../rdd-resolution-table.js";
|
||||
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
|
||||
import { PART_OEUVRE } from "./roll-part-oeuvre.mjs";
|
||||
import { RdDItemArme } from "../item/arme.js";
|
||||
import { RdDBonus } from "../rdd-bonus.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RollDialogAdapter {
|
||||
|
||||
async rollDice(rollData, rollTitle) {
|
||||
const chances = this.computeChances({
|
||||
static async rollDice(rollData, rollTitle) {
|
||||
const chances = RollDialogAdapter.computeChances({
|
||||
carac: rollData.current.carac.value,
|
||||
diff: rollData.current.totaldiff,
|
||||
bonus: rollData.current.bonus,
|
||||
@@ -18,13 +20,13 @@ export class RollDialogAdapter {
|
||||
rollMode: rollData.current.rollmode.key
|
||||
})
|
||||
|
||||
const rolled = await this.rollChances(rollData, chances)
|
||||
this.adjustRollDataForV1(rollData, rolled, rollTitle)
|
||||
const rolled = await RollDialogAdapter.rollChances(rollData, chances)
|
||||
RollDialogAdapter.adjustRollDataForV1(rollData, rolled, rollTitle)
|
||||
|
||||
return rolled
|
||||
}
|
||||
|
||||
computeChances({ carac, diff, bonus, sign, showDice, rollMode }) {
|
||||
static computeChances({ carac, diff, bonus, sign, showDice, rollMode }) {
|
||||
const chances = foundry.utils.duplicate(RdDResolutionTable.computeChances(carac, diff))
|
||||
RdDResolutionTable._updateChancesWithBonus(chances, bonus, diff)
|
||||
RdDResolutionTable._updateChancesFactor(chances, sign)
|
||||
@@ -33,8 +35,10 @@ export class RollDialogAdapter {
|
||||
return chances
|
||||
}
|
||||
|
||||
async rollChances(rollData, chances) {
|
||||
const rolled = await RdDResolutionTable.rollChances(chances, rollData.current.sign, rollData.current.resultat)
|
||||
static async rollChances(rollData, chances) {
|
||||
const rolled = await RdDResolutionTable.rollChances(chances,
|
||||
rollData.current.sign,
|
||||
rollData.current.resultat)
|
||||
rolled.caracValue = rollData.current.carac.value
|
||||
rolled.finalLevel = rollData.current.totaldiff
|
||||
rolled.bonus = rollData.current.bonus ?? 0
|
||||
@@ -42,7 +46,7 @@ export class RollDialogAdapter {
|
||||
return rolled
|
||||
}
|
||||
|
||||
adjustRollDataForV1(rollData, rolled, rollTitle) {
|
||||
static adjustRollDataForV1(rollData, rolled, rollTitle) {
|
||||
// temporaire pour être homogène roll v1
|
||||
rollData.alias = rollData.active.actor.getAlias()
|
||||
// pour experience
|
||||
@@ -57,7 +61,7 @@ export class RollDialogAdapter {
|
||||
const compKey = rollData.current.comp?.key
|
||||
if (compKey) {
|
||||
rollData.competence = rollData.refs[PART_COMP].all.find(it => it.key == compKey)?.comp
|
||||
rollData.jetResistance = rollData.mode.jetResistance
|
||||
rollData.jetResistance = rollData.type.jetResistance
|
||||
}
|
||||
const oeuvreKey = rollData.current.oeuvre?.key
|
||||
if (oeuvreKey) {
|
||||
@@ -87,4 +91,29 @@ export class RollDialogAdapter {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,18 +1,18 @@
|
||||
import { Misc } from "../misc.js";
|
||||
import { RollModeComp } from "./roll-mode-comp.mjs";
|
||||
import { RollModeTache } from "./roll-mode-tache.mjs";
|
||||
import { RollModeAttaque } from "./roll-mode-attaque.mjs";
|
||||
import { RollModeDefense } from "./roll-mode-defense.mjs";
|
||||
import { RollModeMeditation } from "./roll-mode-meditation.mjs";
|
||||
import { RollModeSort } from "./roll-mode-sort.mjs";
|
||||
import { RollModeOeuvre } from "./roll-mode-oeuvre.mjs";
|
||||
import { RollModeJeu } from "./roll-mode-jeu.mjs";
|
||||
import { RollTypeComp } from "./roll-type-comp.mjs";
|
||||
import { RollTypeTache } from "./roll-type-tache.mjs";
|
||||
import { RollTypeAttaque } from "./roll-type-attaque.mjs";
|
||||
import { RollTypeDefense } from "./roll-type-defense.mjs";
|
||||
import { RollTypeMeditation } from "./roll-type-meditation.mjs";
|
||||
import { RollTypeSort } from "./roll-type-sort.mjs";
|
||||
import { RollTypeOeuvre } from "./roll-type-oeuvre.mjs";
|
||||
import { RollTypeJeu } from "./roll-type-jeu.mjs";
|
||||
|
||||
import { RollPartAction } from "./roll-part-action.mjs";
|
||||
import { RollPartActor } from "./roll-part-actor.mjs";
|
||||
import { RollPartAppelMoral } from "./roll-part-appelmoral.mjs";
|
||||
import { RollPartAstrologique } from "./roll-part-astrologique.mjs";
|
||||
import { RollPartCarac } from "./roll-part-carac.mjs";
|
||||
import { PART_CARAC, RollPartCarac } from "./roll-part-carac.mjs";
|
||||
import { RollPartCoeur } from "./roll-part-coeur.mjs";
|
||||
import { PART_COMP, RollPartComp } from "./roll-part-comp.mjs";
|
||||
import { RollPartConditions } from "./roll-part-conditions.mjs";
|
||||
@@ -25,7 +25,7 @@ import { RollPartMeditation } from "./roll-part-meditation.mjs";
|
||||
import { RollPartMoral } from "./roll-part-moral.mjs";
|
||||
import { RollPartOpponent } from "./roll-part-opponent.mjs";
|
||||
import { RollPartSurEnc } from "./roll-part-surenc.mjs";
|
||||
import { RollPartTricher } from "./roll-part-tricher.mjs";
|
||||
import { PART_TRICHER, RollPartTricher } from "./roll-part-tricher.mjs";
|
||||
import { RollPartTache } from "./roll-part-tache.mjs";
|
||||
import { RollPartOeuvre } from "./roll-part-oeuvre.mjs";
|
||||
import { RollPartSort } from "./roll-part-sort.mjs";
|
||||
@@ -37,23 +37,24 @@ import { RollPartAttaque } from "./roll-part-attaque.mjs";
|
||||
import { RollPartDefense } from "./roll-part-defense.mjs";
|
||||
import { RollDialogAdapter } from "./roll-dialog-adapter.mjs";
|
||||
import { ROLLDIALOG_SECTION } from "./roll-part.mjs";
|
||||
import { ROLL_MODE_COMP } from "./roll-constants.mjs";
|
||||
import { ROLL_TYPE_COMP } from "./roll-constants.mjs";
|
||||
import ChatRollResult from "./chat-roll-result.mjs";
|
||||
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api
|
||||
const doNothing = (dialog) => { }
|
||||
|
||||
const ROLL_MODE_TABS = [
|
||||
new RollModeComp(),
|
||||
new RollModeTache(),
|
||||
new RollModeAttaque(),
|
||||
new RollModeDefense(),
|
||||
// new RollModeParade??
|
||||
// new RollModeEsquive??
|
||||
// new RollModeResistance ??
|
||||
new RollModeSort(),
|
||||
new RollModeMeditation(),
|
||||
new RollModeOeuvre(),
|
||||
new RollModeJeu(),
|
||||
const ALL_ROLL_TYPES = [
|
||||
new RollTypeComp(),
|
||||
new RollTypeTache(),
|
||||
new RollTypeAttaque(),
|
||||
new RollTypeDefense(),
|
||||
new RollTypeSort(),
|
||||
new RollTypeMeditation(),
|
||||
new RollTypeOeuvre(),
|
||||
new RollTypeJeu(),
|
||||
// new RollTypeResistance ??
|
||||
// new RollTypeFixedCarac ??
|
||||
]
|
||||
|
||||
const BASIC_PARTS = new RollBasicParts()
|
||||
@@ -95,7 +96,7 @@ const ROLL_PARTS = [
|
||||
* @extends {Dialog}
|
||||
* # Principes
|
||||
* - une seule fenêtre de dialogue (classe RollDialog)
|
||||
* - plusieurs modes de fonctionnement (classe RollMode)
|
||||
* - plusieurs "types"s de fonctionnement (classe RollType)
|
||||
* - gestion uniforme des modificateurs (classe RollPart)
|
||||
* - un objet rollData contient les informations liées à un jet de dés
|
||||
* - un rollData doit pouvoir être "réduit" pour fournir les informations significatives
|
||||
@@ -106,15 +107,15 @@ const ROLL_PARTS = [
|
||||
* - TODO: une classe de base RollChatMessage gerera les messages correspondant aux résultats du dés
|
||||
* - TODO: réfléchir aux messages supplémentaires gérés par RdDCombat ?
|
||||
*
|
||||
* ## Modes de fonctionnement - RollMode
|
||||
* ## Types de fonctionnement - RollType
|
||||
*
|
||||
* Un mode de fonctionnement (RollMode) détermine quelles parties (RollPart) de la
|
||||
* Un type de fonctionnement (RollType) détermine quelles parties (RollPart) de la
|
||||
* fenêtre RollDialog sont actives, mais aussi quels sont les effets du jet.
|
||||
*
|
||||
* - chaque mode de fonctionnement peut impacter les RollPart utilisés, les données
|
||||
* - chaque type de fonctionnement peut impacter les RollPart utilisés, les données
|
||||
* attendues et ajoutées au rollData.
|
||||
* - chaque mode de fonctionnement peut définir le template de ChatMessage correspondant
|
||||
* - Le mode de fonctionnement détermine aussi quelles sont les effets du jet:
|
||||
* - chaque type de fonctionnement peut définir le template de ChatMessage correspondant
|
||||
* - Le type de fonctionnement détermine aussi quelles sont les effets du jet:
|
||||
* - quelle ChatMessage afficher dans le tchat?
|
||||
* - en cas d'attaque/de défense, quelles sont les suites à donner?
|
||||
* - en cas de lancement de sort, réduire les points de rêve
|
||||
@@ -176,14 +177,16 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
|
||||
foundry.applications.handlebars.loadTemplates({
|
||||
'roll-section': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-section.hbs',
|
||||
'roll-mode': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-mode.hbs',
|
||||
'roll-type': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-type.hbs',
|
||||
'roll-table': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-table.hbs',
|
||||
'roll-ajustements': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-ajustements.hbs',
|
||||
'roll-chances': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-chances.hbs',
|
||||
'roll-button': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-button.hbs',
|
||||
})
|
||||
|
||||
foundry.applications.handlebars.loadTemplates(ROLL_MODE_TABS.map(m => m.template))
|
||||
ChatRollResult.onReady()
|
||||
|
||||
foundry.applications.handlebars.loadTemplates(ALL_ROLL_TYPES.map(m => m.template))
|
||||
foundry.applications.handlebars.loadTemplates(ROLL_PARTS.map(p => p.template))
|
||||
ROLL_PARTS.forEach(p => p.onReady())
|
||||
|
||||
@@ -217,7 +220,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
static async create(rollData, rollOptions = {}) {
|
||||
const rollDialog = new RollDialog(rollData, rollOptions)
|
||||
rollDialog.render(true)
|
||||
@@ -247,43 +250,26 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
// rien pour l'instant
|
||||
}
|
||||
|
||||
constructor(rollData, rollOptions) {
|
||||
super()
|
||||
this.rollData = rollData
|
||||
// const callbacks = this.rollOptions.callbacks.map(c =>
|
||||
// r => r.activve.actor Promise.all(this.rollOptions.callbacks.map(async callback => await callback(rollData.active.actor, rollData)))
|
||||
// )
|
||||
this.rollOptions = {
|
||||
callbacks: [
|
||||
async (actor, r) => await actor.appliquerAjoutExperience(r),
|
||||
async (actor, r) => await actor.appliquerAppelMoral(r),
|
||||
...(rollOptions.callbacks ?? [])
|
||||
],
|
||||
customChatMessage: rollOptions.customChatMessage,
|
||||
onRoll: rollOptions.onRoll ?? doNothing
|
||||
}
|
||||
this.$loadParts()
|
||||
}
|
||||
|
||||
/** pre-configure les paramètres des différentes parties de la fenêtre (par exemple, prépare les listes de caractéristiques/compétences */
|
||||
$loadParts() {
|
||||
const rollData = this.rollData;
|
||||
static $prepareRollData(rollData) {
|
||||
rollData.current = rollData.current ?? {}
|
||||
rollData.selected = rollData.selected ?? {}
|
||||
rollData.mode = rollData.mode ?? {}
|
||||
rollData.mode.retry = rollData.mode.retry ?? false
|
||||
rollData.type = rollData.type ?? {}
|
||||
rollData.type.retry = rollData.type.retry ?? false
|
||||
BASIC_PARTS.restore(rollData)
|
||||
|
||||
const loadedMode = ROLL_MODE_TABS.find(m => m.code == rollData.mode?.current)?.code
|
||||
const allowedModes = ROLL_MODE_TABS.filter(m => m.isAllowed(rollData) && m.visible(rollData)).map(m => m.code)
|
||||
const potential = ALL_ROLL_TYPES.find(m => m.code == rollData.type.current)?.code
|
||||
const allowed = rollData.type.retry && potential
|
||||
? [potential]
|
||||
: (rollData.type.allowed ?? ALL_ROLL_TYPES.filter(m => m.isAllowed(rollData) && m.visible(rollData)).map(m => m.code))
|
||||
const rollType = allowed.find(c => c == rollData.type.current) ?? (allowed.length > 0 ? allowed[0].code : ROLL_TYPE_COMP);
|
||||
|
||||
rollData.mode.allowed = rollData.mode.retry ? [loadedMode] : rollData.mode.allowed ?? ROLL_MODE_TABS.map(m => m.code)
|
||||
rollData.mode.current = allowedModes.find(m => m == rollData.mode?.current) ?? (allowedModes.length > 0 ? allowedModes[0] : ROLL_MODE_COMP)
|
||||
rollData.type.allowed = allowed
|
||||
rollData.type.current = rollType
|
||||
ALL_ROLL_TYPES.find(m => m.code == rollType).setRollDataType(rollData)
|
||||
|
||||
this.getSelectedMode().setRollDataMode(rollData)
|
||||
|
||||
rollData.refs = this.$prepareRefs(rollData)
|
||||
rollData.options = rollData.options ?? { showDice: true, rollMode: game.settings.get("core", "rollMode") }
|
||||
rollData.refs = foundry.utils.mergeObject(rollData.refs ?? {}, Object.fromEntries(ROLL_PARTS.map(p => [p.code, {}])));
|
||||
rollData.options = rollData.options ?? { rollMode: game.settings.get("core", "rollMode") }
|
||||
|
||||
ROLL_PARTS.forEach(p => p.initialize(rollData))
|
||||
ROLL_PARTS.forEach(p => p.restore(rollData))
|
||||
@@ -292,32 +278,62 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
p.loadRefs(rollData)
|
||||
p.prepareContext(rollData)
|
||||
})
|
||||
this.selectMode();
|
||||
return rollData
|
||||
}
|
||||
|
||||
selectMode() {
|
||||
this.rollData.mode.label = this.getSelectedMode().title(this.rollData)
|
||||
this.getSelectedMode().setRollDataMode(this.rollData)
|
||||
this.getSelectedMode().onSelect(this.rollData);
|
||||
}
|
||||
|
||||
$prepareRefs(rollData) {
|
||||
return foundry.utils.mergeObject(rollData.refs ?? {}, Object.fromEntries(ROLL_PARTS.map(p => [p.code, {}])));
|
||||
}
|
||||
|
||||
$saveParts() {
|
||||
const target = BASIC_PARTS.initFrom(this.rollData)
|
||||
ROLL_PARTS.filter(p => p.isActive(this.rollData))
|
||||
.forEach(p => p.store(this.rollData, target))
|
||||
static saveParts(rollData) {
|
||||
const target = BASIC_PARTS.initFrom(rollData)
|
||||
ROLL_PARTS.filter(p => p.isActive(rollData))
|
||||
.forEach(p => p.storeClean(rollData, target))
|
||||
target.attackerRoll = rollData.attackerRoll
|
||||
target.rolled = rollData.rolled
|
||||
target.result = rollData.result
|
||||
target.done = target.done ?? {}
|
||||
return target
|
||||
}
|
||||
|
||||
getActiveParts() {
|
||||
return ROLL_PARTS.filter(p => p.isActive(this.rollData))
|
||||
constructor(rollData, rollOptions) {
|
||||
super()
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
get title() {
|
||||
return this.rollData.title ?? `Jet de dés de ${this.rollData.active.actor.name}`
|
||||
selectType() {
|
||||
const selectedType = this.getSelectedType();
|
||||
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) {
|
||||
@@ -329,24 +345,24 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
this.roll()
|
||||
}
|
||||
)
|
||||
const buttonsMode = this.element.querySelectorAll(`button[name="roll-mode"]`)
|
||||
buttonsMode?.forEach(it => it.addEventListener(
|
||||
const buttonsType = this.element.querySelectorAll(`button[name="roll-type"]`)
|
||||
buttonsType?.forEach(it => it.addEventListener(
|
||||
"click", e => {
|
||||
e.preventDefault()
|
||||
this.rollData.mode.current = e.currentTarget.dataset.mode
|
||||
this.selectMode()
|
||||
this.rollData.type.current = e.currentTarget.dataset.type
|
||||
this.selectType()
|
||||
this.render()
|
||||
}
|
||||
))
|
||||
|
||||
Promise.all(
|
||||
this.getActiveParts().map(async p => await p._onRender(this, context, options))
|
||||
RollDialog.getActiveParts(this.rollData).map(async p => await p._onRender(this, context, options))
|
||||
)
|
||||
}
|
||||
|
||||
getAjustements() {
|
||||
return this.getActiveParts()
|
||||
.map(p => p.getAjustements(this.rollData))
|
||||
static getAjustements(rollData) {
|
||||
return RollDialog.getActiveParts(rollData)
|
||||
.map(p => p.getAjustements(rollData))
|
||||
.reduce((a, b) => a.concat(b))
|
||||
.sort((a, b) => a.diff == undefined ? 1 : b.diff == undefined ? -1 : 0)
|
||||
}
|
||||
@@ -355,28 +371,28 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
return await foundry.applications.handlebars.renderTemplate('roll-table', { carac, diff })
|
||||
}
|
||||
|
||||
|
||||
async _prepareContext() {
|
||||
const rollData = this.rollData
|
||||
|
||||
const modes = ROLL_MODE_TABS.filter(m => m.isAllowed(rollData) && m.visible(rollData))
|
||||
.map(m => m.toModeData(rollData))
|
||||
this.setModeTitle()
|
||||
|
||||
const visibleRollParts = this.getActiveParts()
|
||||
visibleRollParts.forEach(p => p.setExternalFilter(visibleRollParts, rollData))
|
||||
const types = ALL_ROLL_TYPES.filter(m => m.isAllowed(rollData) && m.visible(rollData))
|
||||
.map(m => m.toTypeData(rollData))
|
||||
BASIC_PARTS.loadSurprises(rollData, this.getSelectedType().code)
|
||||
rollData.type.label = this.getSelectedType()?.title(rollData)
|
||||
//TOCHECK: set type.label ?
|
||||
const visibleRollParts = RollDialog.getActiveParts(rollData)
|
||||
visibleRollParts.forEach(p => p.applyExternalImpacts(visibleRollParts, rollData))
|
||||
|
||||
this.setSpecialComp(visibleRollParts);
|
||||
|
||||
visibleRollParts.forEach(p => p.prepareContext(rollData))
|
||||
|
||||
this.calculAjustements()
|
||||
RollDialog.calculAjustements(rollData)
|
||||
|
||||
const templates = this.getActiveParts().map(p => p.toTemplateData())
|
||||
const templates = RollDialog.getActiveParts(rollData).map(p => p.toTemplateData())
|
||||
const context = await super._prepareContext()
|
||||
return foundry.utils.mergeObject(
|
||||
{
|
||||
modes: modes,
|
||||
types: types,
|
||||
templates: templates,
|
||||
rollData: rollData,
|
||||
}, context)
|
||||
@@ -386,42 +402,46 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
const specialComp = visibleRollParts.map(p => p.getSpecialComp(this.rollData))
|
||||
.reduce((a, b) => a.concat(b))
|
||||
if (specialComp.length > 0) {
|
||||
const rollPartComp = this.getActiveParts()
|
||||
const rollPartComp = RollDialog.getActiveParts(this.rollData)
|
||||
.find(it => it.code == PART_COMP);
|
||||
rollPartComp?.setSpecialComp(this.rollData, specialComp)
|
||||
}
|
||||
}
|
||||
|
||||
calculAjustements() {
|
||||
this.rollData.ajustements = this.getAjustements()
|
||||
this.rollData.ajustements.forEach(it => it.isDiff = it.diff != undefined)
|
||||
this.rollData.current.totaldiff = this.rollData.ajustements
|
||||
static calculAjustements(rollData) {
|
||||
rollData.ajustements = RollDialog.getAjustements(rollData)
|
||||
rollData.ajustements.forEach(it => it.isDiff = it.diff != undefined)
|
||||
rollData.current.totaldiff = rollData.ajustements
|
||||
.map(adj => adj.diff)
|
||||
.filter(d => d != undefined)
|
||||
.reduce(Misc.sum(), 0)
|
||||
}
|
||||
|
||||
setModeTitle() {
|
||||
this.rollData.mode.label = this.getSelectedMode()?.title(this.rollData)
|
||||
}
|
||||
|
||||
getSelectedMode() {
|
||||
return ROLL_MODE_TABS.find(m => m.code == this.rollData.mode.current)
|
||||
getSelectedType() {
|
||||
return ALL_ROLL_TYPES.find(m => m.code == this.rollData.type.current)
|
||||
}
|
||||
|
||||
async roll() {
|
||||
this.calculAjustements()
|
||||
const rollData = this.rollData
|
||||
console.info('Roll parts:', this.$saveParts())
|
||||
const rolled = await this.$rollDice(rollData)
|
||||
rollData.rolled = rolled
|
||||
Promise.all(this.rollOptions.callbacks.map(async callback => await callback(rollData.active.actor, rollData)))
|
||||
if (!this.rollOptions.customChatMessage) {
|
||||
rollData.active.actor.$onRollCompetence(this.rollData)
|
||||
}
|
||||
this.rollOptions.onRoll(this)
|
||||
// ROLL_PARTS.filter(p => p.isActive(this.rollData))
|
||||
// .forEach(p => p.validate(this.rollData))
|
||||
|
||||
const roll = RollDialog.saveParts(this.rollData)
|
||||
RollDialog.loadRollData(roll)
|
||||
roll.current.resultat = this.rollData.current[PART_TRICHER]?.resultat ?? -1
|
||||
roll.rolled = await this.$rollDice(roll)
|
||||
roll.result = this.getSelectedType(roll).getResult(roll)
|
||||
console.info('RollDialog.roll:', roll)
|
||||
await Promise.all(this.rollOptions.callbacks.map(async callback => await callback(roll)))
|
||||
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) {
|
||||
await rollData.active.actor.appliquerAjoutExperience(rollData)
|
||||
@@ -429,15 +449,6 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
}
|
||||
|
||||
async $rollDice(rollData) {
|
||||
const adapter = new RollDialogAdapter(ROLL_PARTS);
|
||||
return await adapter.rollDice(rollData, this.rollTitle(rollData));
|
||||
}
|
||||
|
||||
rollTitle(rollData) {
|
||||
return ROLL_PARTS
|
||||
.filter(it => it.section == ROLLDIALOG_SECTION.ACTION)
|
||||
.filter(it => it.isActive(rollData))
|
||||
.map(it => it.title(rollData))
|
||||
.reduce(Misc.joining(' '))
|
||||
return await RollDialogAdapter.rollDice(rollData, this.rollTitle(rollData))
|
||||
}
|
||||
}
|
||||
|
@@ -1,13 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
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 ' : ''}` }
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@@ -1,15 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
@@ -1,54 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
@@ -8,12 +8,12 @@ export class RollPartAction extends RollPart {
|
||||
get section() { return ROLLDIALOG_SECTION.ACTION }
|
||||
|
||||
title(rollData) {
|
||||
return rollData.mode.label
|
||||
return rollData.type.label
|
||||
}
|
||||
|
||||
prepareContext(rollData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
current.verb = rollData.mode.label
|
||||
current.verb = rollData.type.label
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -10,10 +10,8 @@ export class RollPartAstrologique extends RollPartCheckbox {
|
||||
get useCheckboxTemplate() { return false }
|
||||
|
||||
visible(rollData) {
|
||||
return this.$isUsingAstrologie() && (
|
||||
this.isJetChance(rollData)
|
||||
|| this.isLancementRituel(rollData)
|
||||
)
|
||||
return this.$isUsingAstrologie()
|
||||
&& (this.isJetChance(rollData) || this.isLancementRituel(rollData))
|
||||
}
|
||||
|
||||
isLancementRituel(rollData) {
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { Grammar } from "../grammar.js"
|
||||
import { RdDBonus } from "../rdd-bonus.js"
|
||||
import { StatusEffects } from "../settings/status-effects.js"
|
||||
import { ROLL_MODE_ATTAQUE } from "./roll-constants.mjs"
|
||||
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"
|
||||
import { ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs"
|
||||
import { PART_CARAC } from "./roll-part-carac.mjs"
|
||||
import { PART_COMP } from "./roll-part-comp.mjs"
|
||||
import { RollPartSelect } from "./roll-part-select.mjs"
|
||||
@@ -16,7 +15,7 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
get code() { return PART_ATTAQUE }
|
||||
get section() { return ROLLDIALOG_SECTION.CHOIX }
|
||||
|
||||
visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_ATTAQUE) }
|
||||
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_ATTAQUE) }
|
||||
|
||||
loadRefs(rollData) {
|
||||
const refs = this.getRefs(rollData)
|
||||
@@ -28,66 +27,47 @@ 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 }
|
||||
|
||||
static $extractAttaque(action, actor) {
|
||||
static $extractAttaque(attaque, actor) {
|
||||
return {
|
||||
key: `${action.action}::${action.name}`,
|
||||
label: action.name,
|
||||
action: action,
|
||||
key: `${attaque.action}::${attaque.name}`,
|
||||
label: attaque.name,
|
||||
attaque: attaque,
|
||||
tactique: TACTIQUES[0],
|
||||
arme: action.arme,
|
||||
comp: action.comp,
|
||||
}
|
||||
}
|
||||
|
||||
prepareContext(rollData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
const effetsSurprise = rollData.opponent?.actor?.getEffects(it => StatusEffects.niveauSurprise(it, true) > 0) ?? []
|
||||
current.defenseur = effetsSurprise
|
||||
? {
|
||||
surprise: RdDBonus.find(rollData.opponent?.actor?.getSurprise(true)),
|
||||
effects: effetsSurprise
|
||||
}
|
||||
: undefined
|
||||
current.dmg = this.dmgRollV2(rollData, current)
|
||||
current.dmg = RdDBonus.dmgRollV2(rollData, current)
|
||||
}
|
||||
|
||||
getAjustements(rollData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
const tactique = current.tactique
|
||||
const surprise = current.defenseur?.surprise
|
||||
const ajustements = []
|
||||
if (tactique) {
|
||||
ajustements.push({ label: tactique.label, diff: tactique.attaque })
|
||||
if (current.tactique) {
|
||||
ajustements.push({ label: current.tactique.label, diff: current.tactique.attaque })
|
||||
}
|
||||
if (surprise) {
|
||||
ajustements.push({ label: surprise.label, diff: surprise.attaque })
|
||||
if (rollData.opponent?.surprise) {
|
||||
ajustements.push({ label: rollData.opponent.surprise.label, diff: rollData.opponent.surprise.attaque })
|
||||
}
|
||||
return ajustements
|
||||
}
|
||||
|
||||
|
||||
dmgRollV2(rollData, current) {
|
||||
const actor = rollData.active.actor
|
||||
const defender = rollData.opponent.actor
|
||||
const dmgArme = RdDBonus.dmgArme(current.arme, current.action.dommagesArme)
|
||||
const dmg = {
|
||||
total: 0,
|
||||
dmgArme: dmgArme,
|
||||
penetration: current.arme.penetration(),
|
||||
dmgTactique: current.tactique?.dmg ?? 0,
|
||||
dmgParticuliere: 0, // TODO RdDBonus._dmgParticuliere(rollData),
|
||||
dmgSurprise: current.defenseur?.surprise.dmg,
|
||||
mortalite: RdDBonus.mortalite(current.dmg?.mortalite, current.arme.system.mortalite, defender?.isEntite()),
|
||||
dmgActor: RdDBonus.bonusDmg(actor, current.action.carac.key, dmgArme)
|
||||
}
|
||||
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere
|
||||
return dmg;
|
||||
}
|
||||
|
||||
$selectAttaque(rollData, key) {
|
||||
this.selectByKey(rollData, key, 0)
|
||||
this.selectByKey(rollData, key)
|
||||
}
|
||||
|
||||
async _onRender(rollDialog, context, options) {
|
||||
@@ -100,7 +80,6 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
const selectOptions = e.currentTarget.options
|
||||
const index = selectOptions.selectedIndex
|
||||
this.$selectAttaque(rollDialog.rollData, selectOptions[index]?.value)
|
||||
rollDialog.setModeTitle()
|
||||
rollDialog.render()
|
||||
})
|
||||
|
||||
@@ -117,16 +96,14 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
})
|
||||
}
|
||||
|
||||
getExternalPartsFilter(partCode, rollData) {
|
||||
impactOtherPart(part, rollData) {
|
||||
if (this.visible(rollData)) {
|
||||
const current = this.getCurrent(rollData)
|
||||
switch (partCode) {
|
||||
case PART_CARAC: return p => Grammar.equalsInsensitive(current.action.carac.key, p.key)
|
||||
case PART_COMP: return p => p.label == current.comp?.name
|
||||
switch (part.code) {
|
||||
case PART_CARAC: return part.filterCaracs(rollData, [current.attaque.carac.key])
|
||||
case PART_COMP: return part.filterComps(rollData, [current.attaque.comp?.name])
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -36,9 +36,14 @@ export class RollPartCarac extends RollPartSelect {
|
||||
}
|
||||
}
|
||||
|
||||
setFilter(rollData, filter) {
|
||||
filterCaracs(rollData, allowed = []) {
|
||||
allowed = allowed.filter(it => it != undefined)
|
||||
const refs = this.getRefs(rollData)
|
||||
refs.caracs = refs.all.filter(filter)
|
||||
refs.caracs = allowed.length > 0
|
||||
// ? refs.all.filter(it => allowed.includes(Grammar.toLowerCaseNoAccent(it.key)))
|
||||
? refs.all.filter(it => allowed.includes(it.key))
|
||||
: refs.all
|
||||
this.$selectCarac(rollData)
|
||||
}
|
||||
|
||||
prepareContext(rollData) {
|
||||
|
@@ -45,9 +45,14 @@ export class RollPartComp extends RollPartSelect {
|
||||
}
|
||||
}
|
||||
|
||||
setFilter(rollData, filter) {
|
||||
filterComps(rollData, allowed = []) {
|
||||
allowed = allowed.filter(it => it != undefined)
|
||||
const refs = this.getRefs(rollData)
|
||||
refs.comps = refs.all.filter(filter)
|
||||
refs.comps = allowed.length > 0
|
||||
// ? 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) {
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { SYSTEM_RDD } from "../constants.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs";
|
||||
|
||||
const CONDITIONS = "conditions"
|
||||
@@ -50,7 +51,7 @@ export class RollPartConditions extends RollPart {
|
||||
const current = this.getCurrent(rollData)
|
||||
current.min = game.settings.get(SYSTEM_RDD, this.settingMin())
|
||||
current.max = game.settings.get(SYSTEM_RDD, this.settingMax())
|
||||
current.value = current.value ?? 0
|
||||
current.value = Misc.inRange(current.value ?? 0, current.min, current.max)
|
||||
}
|
||||
|
||||
getAjustements(rollData) {
|
||||
@@ -63,12 +64,13 @@ export class RollPartConditions extends RollPart {
|
||||
|
||||
async _onRender(rollDialog, context, options) {
|
||||
const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)
|
||||
|
||||
input?.addEventListener("change", e => {
|
||||
const current = this.getCurrent(rollDialog.rollData)
|
||||
current.value = parseInt(e.currentTarget.value)
|
||||
rollDialog.render()
|
||||
})
|
||||
|
||||
input?.addEventListener("input", e => this.onInputChange(e, rollDialog))
|
||||
}
|
||||
|
||||
onInputChange(event, rollDialog) {
|
||||
this.getCurrent(rollDialog.rollData).value = parseInt(event.currentTarget.value)
|
||||
rollDialog.render()
|
||||
}
|
||||
|
||||
}
|
@@ -1,21 +1,133 @@
|
||||
import { ROLL_MODE_DEFENSE } from "./roll-constants.mjs"
|
||||
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
|
||||
import { ITEM_TYPES } from "../constants.js"
|
||||
import { Grammar } from "../grammar.js"
|
||||
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 class RollPartDefense extends RollPart {
|
||||
export class RollPartDefense extends RollPartSelect {
|
||||
|
||||
get code() { return PART_DEFENSE }
|
||||
get section() { return ROLLDIALOG_SECTION.CHOIX }
|
||||
visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_DEFENSE) }
|
||||
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_DEFENSE) }
|
||||
|
||||
static getDiffAttaque(attackerRoll) {
|
||||
// TODO: rollDataV2?
|
||||
return attackerRoll.diffLibre;
|
||||
}
|
||||
|
||||
loadRefs(rollData) {
|
||||
const refs = this.getRefs(rollData)
|
||||
refs.defenses =[]
|
||||
const attackerRoll = rollData.attackerRoll
|
||||
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)
|
||||
}
|
||||
|
||||
isForceInsuffisante(rollData) {
|
||||
return true
|
||||
static $extractEsquive(esquive, defenseur) {
|
||||
return {
|
||||
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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,10 @@
|
||||
import { DIFF_MODE, DIFF_MODES, ROLL_MODE_MEDITATION, ROLL_MODE_OEUVRE, ROLL_MODE_SORT, ROLL_MODE_TACHE } from "./roll-constants.mjs";
|
||||
import { DIFF, DIFFS, ROLL_TYPE_MEDITATION, ROLL_TYPE_OEUVRE, ROLL_TYPE_SORT, ROLL_TYPE_TACHE } from "./roll-constants.mjs";
|
||||
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs";
|
||||
import { Misc } from "../misc.js";
|
||||
|
||||
export const PART_DIFF = "diff"
|
||||
|
||||
const EXCLUDED_ROLL_MODES = [ROLL_MODE_TACHE, ROLL_MODE_MEDITATION, ROLL_MODE_SORT, ROLL_MODE_OEUVRE]
|
||||
const EXCLUDED_ROLL_TYPES = [ROLL_TYPE_TACHE, ROLL_TYPE_MEDITATION, ROLL_TYPE_SORT, ROLL_TYPE_OEUVRE]
|
||||
|
||||
export class RollPartDiff extends RollPart {
|
||||
|
||||
@@ -14,42 +15,48 @@ export class RollPartDiff extends RollPart {
|
||||
const current = this.getCurrent(rollData)
|
||||
const saved = this.getSaved(rollData)
|
||||
current.value = saved?.value ?? current.value ?? 0
|
||||
current.mode = saved?.mode ?? current.mode
|
||||
current.type = saved?.type ?? current.type
|
||||
}
|
||||
|
||||
store(rollData, targetData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
this.setSaved(targetData, {
|
||||
value: current.value,
|
||||
mode: current.mode
|
||||
type: current.type
|
||||
})
|
||||
}
|
||||
|
||||
visible(rollData) {
|
||||
if (EXCLUDED_ROLL_MODES.includes(rollData.mode.current)) {
|
||||
if (EXCLUDED_ROLL_TYPES.includes(rollData.type.current)) {
|
||||
return false
|
||||
}
|
||||
const current = this.getCurrent(rollData)
|
||||
/* TODO: affiner les cas où afficher ou non. devrait s'afficher pour les jets basiques (même si pas d'opposant sélectionné)*/
|
||||
return Object.values(DIFF_MODE).includes(current.mode)
|
||||
return Object.values(DIFF).includes(current.type)
|
||||
}
|
||||
|
||||
prepareContext(rollData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
const diffMode = DIFF_MODES[current.mode] ?? DIFF_MODES[DIFF_MODE.AUCUN]
|
||||
const diffType = DIFFS[current.type] ?? DIFFS[DIFF.AUCUN]
|
||||
foundry.utils.mergeObject(current,
|
||||
{
|
||||
mode: diffMode.key,
|
||||
label: diffMode?.label ?? '',
|
||||
value: current.value ?? 0,
|
||||
disabled: !diffMode.libre,
|
||||
type: diffType.key,
|
||||
label: diffType?.label ?? '',
|
||||
disabled: !diffType.libre,
|
||||
value: Misc.inRange(current.value ?? 0, -10, diffType.max),
|
||||
min: -10,
|
||||
max: diffMode.max
|
||||
max: diffType.max
|
||||
},
|
||||
{ inplace: true }
|
||||
)
|
||||
}
|
||||
|
||||
setDiff(rollData, diffDefense) {
|
||||
const current = this.getCurrent(rollData)
|
||||
current.value = diffDefense.diff
|
||||
current.type = diffDefense.type
|
||||
}
|
||||
|
||||
getAjustements(rollData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
return [{
|
||||
@@ -61,10 +68,12 @@ export class RollPartDiff extends RollPart {
|
||||
async _onRender(rollDialog, context, options) {
|
||||
const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)
|
||||
|
||||
input?.addEventListener("change", e => {
|
||||
this.getCurrent(rollDialog.rollData).value = parseInt(e.currentTarget.value)
|
||||
rollDialog.render()
|
||||
})
|
||||
input?.addEventListener("input", e => this.onInputChange(e, rollDialog))
|
||||
}
|
||||
|
||||
onInputChange(event, rollDialog) {
|
||||
this.getCurrent(rollDialog.rollData).value = parseInt(event.currentTarget.value)
|
||||
rollDialog.render()
|
||||
}
|
||||
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
import { Grammar } from "../grammar.js"
|
||||
import { ITEM_TYPES } from "../constants.js"
|
||||
import { CARACS } from "../rdd-carac.js"
|
||||
import { ROLL_MODE_JEU } from "./roll-constants.mjs"
|
||||
import { ROLL_TYPE_JEU } from "./roll-constants.mjs"
|
||||
import { PART_CARAC } from "./roll-part-carac.mjs"
|
||||
import { PART_COMP } from "./roll-part-comp.mjs"
|
||||
import { RollPartSelect } from "./roll-part-select.mjs"
|
||||
@@ -17,7 +17,7 @@ export class RollPartJeu extends RollPartSelect {
|
||||
get section() { return ROLLDIALOG_SECTION.CHOIX }
|
||||
|
||||
isValid(rollData) { return rollData.active.actor.isPersonnage() }
|
||||
visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_JEU) }
|
||||
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_JEU) }
|
||||
|
||||
loadRefs(rollData) {
|
||||
const refs = this.getRefs(rollData)
|
||||
@@ -68,8 +68,8 @@ export class RollPartJeu extends RollPartSelect {
|
||||
|
||||
prepareContext(rollData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
if (rollData.mode.current == ROLL_MODE_JEU && current) {
|
||||
rollData.mode.opposed = true
|
||||
if (rollData.type.current == ROLL_TYPE_JEU && current) {
|
||||
rollData.type.opposed = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,17 +86,16 @@ export class RollPartJeu extends RollPartSelect {
|
||||
const selectOptions = e.currentTarget.options
|
||||
const index = selectOptions.selectedIndex
|
||||
this.$selectJeu(rollDialog.rollData, selectOptions[index]?.value)
|
||||
rollDialog.setModeTitle()
|
||||
rollDialog.render()
|
||||
})
|
||||
}
|
||||
|
||||
getExternalPartsFilter(partCode, rollData) {
|
||||
impactOtherPart(part, rollData) {
|
||||
if (this.visible(rollData)) {
|
||||
const current = this.getCurrent(rollData)
|
||||
switch (partCode) {
|
||||
case PART_CARAC: return p => current.caracs?.includes(Grammar.toLowerCaseNoAccent(p.key))
|
||||
case PART_COMP: return p => p.label == current.comp?.name
|
||||
switch (part.code) {
|
||||
case PART_CARAC: return part.filterCaracs(rollData, current.caracs)
|
||||
case PART_COMP: return part.filterComps(rollData,[current.comp?.name])
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
|
@@ -1,9 +1,9 @@
|
||||
import { ITEM_TYPES } from "../constants.js"
|
||||
import { Grammar } from "../grammar.js"
|
||||
import { RdDCarac } from "../rdd-carac.js"
|
||||
import { CARACS, RdDCarac } from "../rdd-carac.js"
|
||||
import { RdDTimestamp } from "../time/rdd-timestamp.js"
|
||||
import { TMRUtility } from "../tmr-utility.js"
|
||||
import { ROLL_MODE_MEDITATION } from "./roll-constants.mjs"
|
||||
import { ROLL_TYPE_MEDITATION } from "./roll-constants.mjs"
|
||||
import { PART_CARAC } from "./roll-part-carac.mjs"
|
||||
import { PART_COMP } from "./roll-part-comp.mjs"
|
||||
import { RollPartSelect } from "./roll-part-select.mjs"
|
||||
@@ -17,7 +17,7 @@ export class RollPartMeditation extends RollPartSelect {
|
||||
get section() { return ROLLDIALOG_SECTION.CHOIX }
|
||||
|
||||
isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() }
|
||||
visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_MEDITATION) }
|
||||
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_MEDITATION) }
|
||||
|
||||
loadRefs(rollData) {
|
||||
const refs = this.getRefs(rollData)
|
||||
@@ -86,7 +86,6 @@ export class RollPartMeditation extends RollPartSelect {
|
||||
const index = selectOptions.selectedIndex
|
||||
this.$selectMeditation(rollDialog.rollData, selectOptions[index]?.value)
|
||||
rollDialog.render()
|
||||
rollDialog.setModeTitle()
|
||||
})
|
||||
|
||||
this.setupListenerCondition(rollDialog, 'isComportement')
|
||||
@@ -104,12 +103,12 @@ export class RollPartMeditation extends RollPartSelect {
|
||||
})
|
||||
}
|
||||
|
||||
getExternalPartsFilter(partCode, rollData) {
|
||||
impactOtherPart(part, rollData) {
|
||||
if (this.visible(rollData)) {
|
||||
const current = this.getCurrent(rollData)
|
||||
switch (partCode) {
|
||||
case PART_CARAC: return p => RdDCarac.isIntellect(p.key)
|
||||
case PART_COMP: return p => p.label == current.comp?.name
|
||||
switch (part.code) {
|
||||
case PART_CARAC: return part.filterCaracs(rollData, [CARACS.INTELLECT])
|
||||
case PART_COMP: return part.filterComps(rollData,[current.comp?.name])
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import { ITEM_TYPES } from "../constants.js"
|
||||
import { Grammar } from "../grammar.js"
|
||||
import { Misc } from "../misc.js"
|
||||
import { CARACS } from "../rdd-carac.js"
|
||||
import { ROLL_MODE_OEUVRE } from "./roll-constants.mjs"
|
||||
import { ROLL_TYPE_OEUVRE } from "./roll-constants.mjs"
|
||||
import { PART_CARAC } from "./roll-part-carac.mjs"
|
||||
import { PART_COMP } from "./roll-part-comp.mjs"
|
||||
import { RollPartSelect } from "./roll-part-select.mjs"
|
||||
@@ -38,7 +37,7 @@ export class RollPartOeuvre extends RollPartSelect {
|
||||
get section() { return ROLLDIALOG_SECTION.CHOIX }
|
||||
|
||||
isValid(rollData) { return rollData.active.actor.isPersonnage() }
|
||||
visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_OEUVRE) }
|
||||
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_OEUVRE) }
|
||||
|
||||
loadRefs(rollData) {
|
||||
const refs = this.getRefs(rollData)
|
||||
@@ -59,6 +58,7 @@ export class RollPartOeuvre extends RollPartSelect {
|
||||
label: oeuvre.name,
|
||||
art: art,
|
||||
caracs: art.caracs(oeuvre),
|
||||
qualite: oeuvre.system.niveau,
|
||||
value: -oeuvre.system.niveau,
|
||||
oeuvre: oeuvre,
|
||||
comp: actor.getCompetence(art.competence(oeuvre))
|
||||
@@ -80,17 +80,16 @@ export class RollPartOeuvre extends RollPartSelect {
|
||||
const selectOptions = e.currentTarget.options
|
||||
const index = selectOptions.selectedIndex
|
||||
this.$selectOeuvre(rollDialog.rollData, selectOptions[index]?.value)
|
||||
rollDialog.setModeTitle()
|
||||
rollDialog.render()
|
||||
})
|
||||
}
|
||||
|
||||
getExternalPartsFilter(partCode, rollData) {
|
||||
impactOtherPart(part, rollData) {
|
||||
if (this.visible(rollData)) {
|
||||
const current = this.getCurrent(rollData)
|
||||
switch (partCode) {
|
||||
case PART_CARAC: return p => current.caracs?.includes(Grammar.toLowerCaseNoAccent(p.key))
|
||||
case PART_COMP: return p => p.label == current.comp?.name
|
||||
switch (part.code) {
|
||||
case PART_CARAC: return part.filterCaracs(rollData, current.caracs)
|
||||
case PART_COMP: return part.filterComps(rollData,[current.comp?.name])
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
|
@@ -7,6 +7,6 @@ export class RollPartOpponent extends RollPart {
|
||||
get code() { return OPPONENT }
|
||||
get section() { return ROLLDIALOG_SECTION.ACTION }
|
||||
|
||||
visible(rollData) { return rollData.mode.opposed }
|
||||
visible(rollData) { return rollData.type.opposed }
|
||||
title(rollData) { return rollData.opponent?.name ?? '' }
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Misc } from "../misc.js"
|
||||
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"
|
||||
import { StatusEffects } from "../settings/status-effects.js"
|
||||
import { ROLL_MODE_ATTAQUE, ROLL_MODE_DEFENSE } from "./roll-constants.mjs"
|
||||
import { PART_ATTAQUE, RollPartAttaque } from "./roll-part-attaque.mjs"
|
||||
import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs"
|
||||
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
|
||||
|
||||
export const PART_SIGN = "sign"
|
||||
@@ -23,13 +23,8 @@ export class RollPartSign extends RollPart {
|
||||
this.setSaved(targetData, this.getCurrent(rollData))
|
||||
}
|
||||
|
||||
// visible(rollData) {
|
||||
// const current = this.getCurrent(rollData)
|
||||
// return current.surprise != ''
|
||||
// }
|
||||
|
||||
isCombat(rollData) {
|
||||
return [ROLL_MODE_ATTAQUE, ROLL_MODE_DEFENSE].includes(rollData.mode.current) || rollData.mode.isCombat
|
||||
return [ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE].includes(rollData.type.current) || rollData.type.isCombat
|
||||
}
|
||||
|
||||
prepareContext(rollData) {
|
||||
@@ -37,56 +32,53 @@ export class RollPartSign extends RollPart {
|
||||
}
|
||||
|
||||
setFromState(rollData) {
|
||||
if (rollData.mode.retry) {
|
||||
if (rollData.type.retry) {
|
||||
return
|
||||
}
|
||||
const actor = rollData.active.actor;
|
||||
const isCombat = this.isCombat(rollData)
|
||||
const current = this.getCurrent(rollData)
|
||||
current.surprise = actor.getSurprise(isCombat)
|
||||
current.armeDisparate = isCombat && current.armeDisparate
|
||||
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.diviseur = 1
|
||||
if (isCombat && actor.isDemiReve()) {
|
||||
current.reasons.push('Demi-rêve en combat')
|
||||
}
|
||||
if (current.surprise == 'demi') {
|
||||
current.diviseur *= 2
|
||||
}
|
||||
|
||||
if (isCombat && actor.isDemiReve()) {
|
||||
current.reasons.push('Demi-rêve en combat')
|
||||
}
|
||||
if (this.isParadeArmeDisparate(current)) {
|
||||
current.diviseur *= 2
|
||||
current.reasons.push('Armes disparates')
|
||||
}
|
||||
if (this.isAttaqueFinesse(rollData)) {
|
||||
current.diviseur *= 2
|
||||
current.reasons.push('Attaque en finesse')
|
||||
current.reasons.push('Particulière en finesse')
|
||||
}
|
||||
if (this.isForceInsuffisante(rollData)) {
|
||||
current.diviseur *= 2
|
||||
current.reasons.push('Force insuffisante')
|
||||
|
||||
if (!ReglesOptionnelles.isUsing('tripleSignificative')) {
|
||||
current.diviseur = Math.min(current.diviseur, 4);
|
||||
}
|
||||
|
||||
current.reason = current.reasons.join(', ')
|
||||
}
|
||||
|
||||
isForceInsuffisante(rollData) {
|
||||
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
|
||||
isAttaqueFinesse(rollData) {
|
||||
return ROLL_TYPE_DEFENSE == rollData.type.current && rollData.attaque?.particuliere == 'finesse'
|
||||
}
|
||||
|
||||
isAttaqueFinesse(rollData) {
|
||||
// this.rollData.selected[PART_DEFENSE] && attaquant avec particulière en finesse
|
||||
return ROLL_MODE_DEFENSE == rollData.mode.current && true
|
||||
isParadeArmeDisparate(current) {
|
||||
return current.armeDisparate
|
||||
}
|
||||
|
||||
getAjustements(rollData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
if (current.surprise == 'demi') {
|
||||
return [{ label: 'Significative requise ' + Misc.getFractionOneN(current.diviseur), diff: undefined }]
|
||||
return [
|
||||
{ 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 []
|
||||
}
|
||||
@@ -100,4 +92,7 @@ export class RollPartSign extends RollPart {
|
||||
})
|
||||
}
|
||||
|
||||
setArmeDisparate(rollData, armeDisparate) {
|
||||
this.getCurrent(rollData).armeDisparate = armeDisparate
|
||||
}
|
||||
}
|
@@ -1,11 +1,12 @@
|
||||
import { ITEM_TYPES } from "../constants.js"
|
||||
import { ROLL_MODE_SORT } from "./roll-constants.mjs"
|
||||
import { ROLL_TYPE_SORT } from "./roll-constants.mjs"
|
||||
import { PART_CARAC } from "./roll-part-carac.mjs"
|
||||
import { PART_COMP } from "./roll-part-comp.mjs"
|
||||
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
|
||||
import { TMRUtility } from "../tmr-utility.js"
|
||||
import { RdDItemSort } from "../item-sort.js"
|
||||
import { RollPartSelect } from "./roll-part-select.mjs"
|
||||
import { CARACS } from "../rdd-carac.js"
|
||||
|
||||
export const PART_SORT = "sort"
|
||||
|
||||
@@ -17,7 +18,7 @@ export class RollPartSort extends RollPartSelect {
|
||||
get section() { return ROLLDIALOG_SECTION.CHOIX }
|
||||
|
||||
isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() }
|
||||
visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_SORT) }
|
||||
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_SORT) }
|
||||
|
||||
loadRefs(rollData) {
|
||||
const refs = this.getRefs(rollData)
|
||||
@@ -97,7 +98,6 @@ export class RollPartSort extends RollPartSelect {
|
||||
const selectOptions = e.currentTarget.options
|
||||
const index = selectOptions.selectedIndex
|
||||
this.$selectSort(rollDialog.rollData, selectOptions[index]?.value)
|
||||
rollDialog.setModeTitle()
|
||||
rollDialog.render()
|
||||
})
|
||||
|
||||
@@ -115,12 +115,12 @@ export class RollPartSort extends RollPartSelect {
|
||||
})
|
||||
}
|
||||
|
||||
getExternalPartsFilter(partCode, rollData) {
|
||||
impactOtherPart(part, rollData) {
|
||||
if (this.visible(rollData)) {
|
||||
const current = this.getCurrent(rollData)
|
||||
switch (partCode) {
|
||||
case PART_CARAC: return p => p.key == 'reve'
|
||||
case PART_COMP: return p => current.draconics?.includes(p.label)
|
||||
switch (part.code) {
|
||||
case PART_CARAC: return part.filterCaracs(rollData, [CARACS.REVE])
|
||||
case PART_COMP: return part.filterComps(rollData,current.draconics ?? [])
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { ITEM_TYPES } from "../constants.js"
|
||||
import { Grammar } from "../grammar.js"
|
||||
import { ROLL_MODE_TACHE } from "./roll-constants.mjs"
|
||||
import { ROLL_TYPE_TACHE } from "./roll-constants.mjs"
|
||||
import { PART_CARAC } from "./roll-part-carac.mjs"
|
||||
import { PART_COMP } from "./roll-part-comp.mjs"
|
||||
import { RollPartSelect } from "./roll-part-select.mjs"
|
||||
@@ -14,19 +14,19 @@ export class RollPartTache extends RollPartSelect {
|
||||
get section() { return ROLLDIALOG_SECTION.CHOIX }
|
||||
|
||||
isValid(rollData) { return rollData.active.actor.isPersonnage() }
|
||||
visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_TACHE) }
|
||||
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_TACHE) }
|
||||
|
||||
loadRefs(rollData) {
|
||||
const refs = this.getRefs(rollData)
|
||||
refs.taches = rollData.active.actor.itemTypes[ITEM_TYPES.tache]
|
||||
.filter(tache => tache.system.points_de_tache_courant < tache.system.points_de_tache)
|
||||
.map(tache => RollPartTache.$extractTache(tache, rollData.active.actor))
|
||||
.filter(tache => tache.system.points_de_tache_courant < tache.system.points_de_tache)
|
||||
.map(tache => RollPartTache.$extractTache(tache, rollData.active.actor))
|
||||
if (refs.taches.length > 0) {
|
||||
this.$selectTache(rollData)
|
||||
}
|
||||
}
|
||||
choices(refs) { return refs.taches }
|
||||
|
||||
|
||||
static $extractTache(tache, actor) {
|
||||
return {
|
||||
key: tache.id,
|
||||
@@ -48,17 +48,16 @@ export class RollPartTache extends RollPartSelect {
|
||||
const selectOptions = e.currentTarget.options
|
||||
const index = selectOptions.selectedIndex
|
||||
this.$selectTache(rollDialog.rollData, selectOptions[index]?.value)
|
||||
rollDialog.setModeTitle()
|
||||
rollDialog.render()
|
||||
})
|
||||
}
|
||||
|
||||
getExternalPartsFilter(partCode, rollData) {
|
||||
impactOtherPart(part, rollData) {
|
||||
if (this.visible(rollData)) {
|
||||
const current = this.getCurrent(rollData)
|
||||
switch (partCode) {
|
||||
case PART_CARAC: return p => Grammar.equalsInsensitive(p.key, current?.tache.system.carac)
|
||||
case PART_COMP: return p => p.label == current?.comp.name
|
||||
switch (part.code) {
|
||||
case PART_CARAC: return part.filterCaracs(rollData, [current?.tache.system.carac])
|
||||
case PART_COMP: return part.filterComps(rollData, [current.comp?.name])
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { Misc } from "../misc.js"
|
||||
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
|
||||
|
||||
const PART_TRICHER = "tricher"
|
||||
export const PART_TRICHER = "tricher"
|
||||
|
||||
export class RollPartTricher extends RollPart {
|
||||
|
||||
@@ -11,21 +12,20 @@ export class RollPartTricher extends RollPart {
|
||||
|
||||
prepareContext(rollData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
if (current.resultat == undefined) {
|
||||
current.resultat = -1
|
||||
}
|
||||
current.resultat = Misc.inRange(current.resultat == undefined ? -1 : current.resultat, -1, 100)
|
||||
}
|
||||
|
||||
getAjustements(rollData) {
|
||||
rollData.current.resultat = this.getCurrent(rollData).resultat
|
||||
return []
|
||||
}
|
||||
|
||||
async _onRender(rollDialog, context, options) {
|
||||
const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)
|
||||
|
||||
input?.addEventListener("change", e => {
|
||||
this.getCurrent(rollDialog.rollData).resultat = parseInt(e.currentTarget.value)
|
||||
})
|
||||
input?.addEventListener("input", e => this.onInputChange(e, rollDialog))
|
||||
}
|
||||
|
||||
onInputChange(event, rollDialog) {
|
||||
this.getCurrent(rollDialog.rollData).resultat = parseInt(event.currentTarget.value)
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,3 @@
|
||||
import { Misc } from "../misc.js"
|
||||
|
||||
export const ROLLDIALOG_SECTION = {
|
||||
ACTION: 'action',
|
||||
CARAC: 'carac',
|
||||
@@ -53,14 +51,30 @@ export class RollPart {
|
||||
}
|
||||
|
||||
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
|
||||
* @returns une chaîne vide si rien ne doit être affiché
|
||||
*/
|
||||
title() { return '' }
|
||||
isRollMode(rollData, mode) { return rollData.mode.current == mode }
|
||||
isRollType(rollData, type) { return rollData.type.current == type }
|
||||
|
||||
isActive(rollData) { return this.isValid(rollData) && this.visible(rollData) }
|
||||
isValid(rollData) { return true }
|
||||
@@ -70,18 +84,19 @@ export class RollPart {
|
||||
loadRefs(rollData) { }
|
||||
|
||||
prepareContext(rollData) { }
|
||||
|
||||
/** permet de sauvegarder dans rollData les informations (cas des champs edit) */
|
||||
validate(rollData) {}
|
||||
|
||||
/** ---- cross roll-part filtering ---- */
|
||||
setFilter(rollData, filter) { }
|
||||
applyImpact(rollData, filter) { }
|
||||
getSpecialComp(rollData) { return [] }
|
||||
setSpecialComp(comps) { }
|
||||
|
||||
getExternalPartsFilter(partCode, rollData) { return undefined }
|
||||
setExternalFilter(visibleRollParts, rollData) {
|
||||
const predicate = Misc.and(
|
||||
visibleRollParts.map(p => p.getExternalPartsFilter(this.code, rollData)).filter(f => f != undefined)
|
||||
)
|
||||
this.setFilter(rollData, predicate);
|
||||
impactOtherPart(partCode, rollData) { }
|
||||
|
||||
applyExternalImpacts(rollParts, rollData) {
|
||||
rollParts.forEach(part => part.impactOtherPart(this, rollData))
|
||||
}
|
||||
|
||||
toTemplateData() {
|
||||
|
13
module/roll/roll-type-attaque.mjs
Normal file
13
module/roll/roll-type-attaque.mjs
Normal file
@@ -0,0 +1,13 @@
|
||||
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)
|
||||
}
|
||||
}
|
10
module/roll/roll-type-comp.mjs
Normal file
10
module/roll/roll-type-comp.mjs
Normal file
@@ -0,0 +1,10 @@
|
||||
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 ' : ''}` }
|
||||
|
||||
}
|
17
module/roll/roll-type-defense.mjs
Normal file
17
module/roll/roll-type-defense.mjs
Normal file
@@ -0,0 +1,17 @@
|
||||
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)
|
||||
}
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
import { PART_JEU } from "./roll-part-jeu.mjs"
|
||||
import { RollMode } from "./roll-mode.mjs"
|
||||
import { ROLL_MODE_JEU } from "./roll-constants.mjs"
|
||||
import { RollType } from "./roll-type.mjs"
|
||||
import { ROLL_TYPE_JEU } from "./roll-constants.mjs"
|
||||
|
||||
export class RollModeJeu extends RollMode {
|
||||
get code() { return ROLL_MODE_JEU }
|
||||
export class RollTypeJeu extends RollType {
|
||||
get code() { return ROLL_TYPE_JEU }
|
||||
get name() { return `Jouer` }
|
||||
|
||||
visible(rollData) { return rollData.active.actor.isPersonnage() }
|
@@ -1,9 +1,9 @@
|
||||
import { DIFF_MODE, ROLL_MODE_MEDITATION } from "./roll-constants.mjs"
|
||||
import { DIFF, ROLL_TYPE_MEDITATION } from "./roll-constants.mjs"
|
||||
import { PART_MEDITATION } from "./roll-part-meditation.mjs"
|
||||
import { RollMode } from "./roll-mode.mjs"
|
||||
import { RollType } from "./roll-type.mjs"
|
||||
|
||||
export class RollModeMeditation extends RollMode {
|
||||
get code() { return ROLL_MODE_MEDITATION }
|
||||
export class RollTypeMeditation extends RollType {
|
||||
get code() { return ROLL_TYPE_MEDITATION }
|
||||
get name() { return `Méditation draconique` }
|
||||
|
||||
visible(rollData) { return rollData.active.actor.isHautRevant() }
|
||||
@@ -14,6 +14,6 @@ export class RollModeMeditation extends RollMode {
|
||||
}
|
||||
|
||||
onSelect(rollData) {
|
||||
this.setDiffMode(rollData, DIFF_MODE.AUCUN)
|
||||
this.setDiffType(rollData, DIFF.AUCUN)
|
||||
}
|
||||
}
|
28
module/roll/roll-type-oeuvre.mjs
Normal file
28
module/roll/roll-type-oeuvre.mjs
Normal file
@@ -0,0 +1,28 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
14
module/roll/roll-type-sort.mjs
Normal file
14
module/roll/roll-type-sort.mjs
Normal file
@@ -0,0 +1,14 @@
|
||||
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)
|
||||
}
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
import { DIFF_MODE, ROLL_MODE_TACHE } from "./roll-constants.mjs"
|
||||
import { DIFF, ROLL_TYPE_TACHE } from "./roll-constants.mjs"
|
||||
import { PART_TACHE } from "./roll-part-tache.mjs"
|
||||
import { RollMode } from "./roll-mode.mjs"
|
||||
import { RollType } from "./roll-type.mjs"
|
||||
|
||||
export class RollModeTache extends RollMode {
|
||||
get code() { return ROLL_MODE_TACHE }
|
||||
export class RollTypeTache extends RollType {
|
||||
get code() { return ROLL_TYPE_TACHE }
|
||||
get name() { return `Travailler à une tâche` }
|
||||
|
||||
visible(rollData) { return rollData.active.actor.isPersonnage() }
|
||||
@@ -14,6 +14,6 @@ export class RollModeTache extends RollMode {
|
||||
}
|
||||
|
||||
onSelect(rollData) {
|
||||
this.setDiffMode(rollData, DIFF_MODE.AUCUN)
|
||||
this.setDiffType(rollData, DIFF.AUCUN)
|
||||
}
|
||||
}
|
59
module/roll/roll-type.mjs
Normal file
59
module/roll/roll-type.mjs
Normal file
@@ -0,0 +1,59 @@
|
||||
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
|
||||
}
|
||||
}
|
@@ -2,10 +2,12 @@ import { SYSTEM_RDD } from "../constants.js"
|
||||
import { Misc } from "../misc.js"
|
||||
|
||||
export const EXPORT_CSV_SCRIPTARIUM = 'export-csv-scriptarium'
|
||||
export const ROLL_DIALOG_V2 = 'roll-drialog-v2'
|
||||
export const ROLL_DIALOG_V2 = 'roll-dialog-v2'
|
||||
export const ROLL_DIALOG_V2_TEST = 'roll-dialog-v2-test'
|
||||
|
||||
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_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 },
|
||||
]
|
||||
|
||||
@@ -56,7 +58,7 @@ export class OptionsAvancees extends FormApplication {
|
||||
return formData
|
||||
}
|
||||
|
||||
static getSettingKey(name){
|
||||
static getSettingKey(name) {
|
||||
return `${SYSTEM_RDD}.${this._getId(name)}`
|
||||
}
|
||||
|
||||
|
@@ -13,6 +13,7 @@ const listeReglesOptionnelles = [
|
||||
|
||||
{ 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: '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: '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" },
|
||||
|
@@ -1,4 +1,6 @@
|
||||
import { SYSTEM_RDD } from "../constants.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { RdDBonus } from "../rdd-bonus.js";
|
||||
|
||||
export const STATUSES = {
|
||||
StatusGrappling: 'grappling',
|
||||
@@ -12,9 +14,11 @@ export const STATUSES = {
|
||||
StatusBleeding: 'bleeding',
|
||||
StatusDead: 'dead',
|
||||
StatusDemiReve: 'demi-reve',
|
||||
StatusForceWeak: 'force insuffisante',
|
||||
}
|
||||
|
||||
const demiReveStatusEffect = { rdd: true, id: STATUSES.StatusDemiReve, name: 'EFFECT.StatusDemiReve', img: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd12.svg' };
|
||||
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/assets/actions/sort.svg' };
|
||||
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.StatusGrappled, tint: '#ff9900', name: 'EFFECT.StatusGrappled', img: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.webp' },
|
||||
@@ -29,15 +33,15 @@ const rddStatusEffects = [
|
||||
|
||||
{ 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' },
|
||||
demiReveStatusEffect
|
||||
demiReveStatusEffect,
|
||||
forceWeakStatusEffect
|
||||
];
|
||||
|
||||
const statusDemiSurprise = new Set([STATUSES.StatusStunned, STATUSES.StatusProne, STATUSES.StatusRestrained])
|
||||
const statusDemiSurprise = new Set([STATUSES.StatusStunned, STATUSES.StatusProne, STATUSES.StatusRestrained, STATUSES.StatusForceWeak])
|
||||
const statusSurpriseTotale = new Set([STATUSES.StatusUnconscious, STATUSES.StatusBlind, STATUSES.StatusComma])
|
||||
|
||||
export class StatusEffects extends FormApplication {
|
||||
|
||||
|
||||
static onReady() {
|
||||
const rddEffectIds = rddStatusEffects.map(it => it.id);
|
||||
rddStatusEffects.forEach(it => {
|
||||
@@ -67,6 +71,27 @@ export class StatusEffects extends FormApplication {
|
||||
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) {
|
||||
if (statusSurpriseTotale.intersects(effect.statuses)) {
|
||||
return 2
|
||||
|
@@ -6,16 +6,14 @@
|
||||
<span class="competence-value"></span>
|
||||
<span class="initiative-value">Initiative</span>
|
||||
</li>
|
||||
{{#each combat as |action key|}}
|
||||
<li class="item flexrow list-item"
|
||||
data-item-id="{{action._id}}"
|
||||
data-arme-name="{{action.arme.name}}"
|
||||
data-competence-name="{{action.comp.name}}"
|
||||
data-tooltip="{{action.name}}: niveau {{plusMoins action.comp.system.niveau}}">
|
||||
{{#each combat as |action key|}}
|
||||
<li class="item flexrow list-item" data-item-id="{{action._id}}" data-arme-name="{{action.arme.name}}"
|
||||
data-competence-name="{{action.comp.name}}"
|
||||
data-tooltip="{{action.name}}: niveau {{plusMoins action.comp.system.niveau}}">
|
||||
<span class="list-item-label flexrow">
|
||||
<a class="roll-arme flexrow">
|
||||
{{#if action.arme.img}}
|
||||
<img class="sheet-competence-img" src="{{action.arme.img}}" data-tooltip="{{action.arme.name}}"/>
|
||||
<img class="sheet-competence-img" src="{{action.arme.img}}" data-tooltip="{{action.arme.name}}" />
|
||||
{{/if}}
|
||||
<span>{{action.name}}</span>
|
||||
</a>
|
||||
@@ -23,11 +21,10 @@
|
||||
{{>"systems/foundryvtt-reve-de-dragon/templates/item/icon-arme-broken.hbs" action.arme}}
|
||||
</span>
|
||||
<span class="competence-value">{{plusMoins action.comp.system.niveau}}</span>
|
||||
<span class="competence-value">{{plusMoins action.dmg}}</span>
|
||||
<span class="competence-value">{{plusMoins action.dommagesArme}}</span>
|
||||
<span class="competence-value"></span>
|
||||
<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}}
|
||||
</a>
|
||||
</span>
|
||||
@@ -47,7 +44,7 @@
|
||||
<span class="competence-value"></span>
|
||||
<span class="initiative-value"></span>
|
||||
</li>
|
||||
{{/each}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
<ul class="item-list alterne-list">
|
||||
@@ -57,11 +54,10 @@
|
||||
<span class="item-controls"></span>
|
||||
</li>
|
||||
{{#each empoignades as |emp key|}}
|
||||
<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}}">
|
||||
<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}}">
|
||||
<a class="flex-grow-3 action-empoignade">
|
||||
<img class="sheet-competence-img" src="{{emp.img}}"/>
|
||||
<img class="sheet-competence-img" src="{{emp.img}}" />
|
||||
<span>{{emp.name}}</span>
|
||||
</a>
|
||||
<span class="flex-grow-0-5 flex-group-right">{{emp.system.pointsemp}}</span>
|
||||
|
@@ -16,7 +16,7 @@
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
</span>
|
||||
<ul class="item-list alterne-list">
|
||||
<ul class="item-list alterne-list liste-equipement">
|
||||
<li class="competence-header flexrow">
|
||||
<span class="equipement-nom">Nom</span>
|
||||
{{#unless system.illimite}}
|
||||
|
@@ -15,7 +15,7 @@
|
||||
‐ Valeur: {{numberFormat calc.prixTotalEquipement decimals=2}} Sols
|
||||
{{/if}}
|
||||
</span>
|
||||
<ul class="item-list alterne-list">
|
||||
<ul class="item-list alterne-list liste-equipement">
|
||||
<li class="competence-header flexrow">
|
||||
<span class="equipement-nom">Nom</span>
|
||||
<span class="equipement-detail-buttons">Q.</span>
|
||||
|
@@ -1,5 +1,11 @@
|
||||
<div data-passearme="{{passeArme}}">
|
||||
<h4 class="rdd-roll-etotal"><strong>Echec total en attaque</strong></h4>
|
||||
<h4 class="rdd-roll-etotal">Maladresse à l'attaque:<br>échec
|
||||
{{#if rolled.isETotal}}
|
||||
total
|
||||
{{else}}
|
||||
en demi-surprise
|
||||
{{/if}}
|
||||
</h4>
|
||||
<br>
|
||||
{{#if (eq attacker.type 'personnage')}}
|
||||
{{#unless essais.attaqueChance}}
|
||||
|
@@ -22,61 +22,77 @@
|
||||
{{#if (eq defender.type 'personnage')}}
|
||||
<a class='chat-card-button appel-chance-defense'
|
||||
data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}'>
|
||||
Faire appel à la chance</a>
|
||||
Faire appel à la chance
|
||||
</a>
|
||||
<br>
|
||||
{{/if}}
|
||||
{{#if (and (eq defender.type 'personnage') (gt defender.system.compteurs.destinee.value 0))}}
|
||||
<a class='chat-card-button appel-destinee-defense'
|
||||
data-attackerId='{{attackerId}}' data-attackerTokenId='{{attackerToken.id}}' data-defenderTokenId='{{defenderToken.id}}'>
|
||||
Utiliser la destinée</a>
|
||||
Utiliser la destinée
|
||||
</a>
|
||||
<br>
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
{{else}}
|
||||
{{#each armes as |arme key|}}
|
||||
<a class='chat-card-button parer-button'
|
||||
data-attackerId='{{../attackerId}}' data-defenderTokenId='{{../defenderToken.id}}' data-attackerTokenId='{{../attackerToken.id}}'
|
||||
data-armeid='{{arme._id}}'>
|
||||
Parer avec {{arme.name}}
|
||||
{{#if (or (eq ../attaqueCategorie 'tir') (eq ../attaqueCategorie 'lancer'))}}
|
||||
(difficulté à déterminer)
|
||||
{{else}}à {{../diffLibre }}
|
||||
{{/if}}
|
||||
{{#if (eq arme.typeParade 'sign')}}
|
||||
<span class="rdd-diviseur">×½</span>
|
||||
{{/if}}
|
||||
{{#if arme.nbUsage}}(Utilisations : {{arme.nbUsage}}){{/if}}
|
||||
</a>
|
||||
<br>
|
||||
{{/each}}
|
||||
{{#if mainsNues}}
|
||||
<a class='chat-card-button parer-button'
|
||||
data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}'
|
||||
data-armeid='{{arme._id}}' data-competence='{{arme.system.competence}}'>
|
||||
Parer à mains nues à {{diffLibre}}{{#if arme.nbUsage}} (Utilisations : {{arme.nbUsage}}){{/if}}
|
||||
{{#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>
|
||||
{{/if}}
|
||||
{{#if (ne attaqueCategorie 'tir')}}
|
||||
{{#each esquives as |esquive key|}}
|
||||
<a class='chat-card-button esquiver-button'
|
||||
data-attackerId='{{../attackerId}}' data-defenderTokenId='{{../defenderToken.id}}' data-attackerTokenId='{{../attackerToken.id}}'
|
||||
data-compid='{{esquive._id}}' data-competence='{{esquive.name}}'>
|
||||
{{esquive.name}}
|
||||
{{#if (or (eq ../attaqueCategorie 'tir') (eq ../attaqueCategorie 'lancer'))}}
|
||||
(difficulté à déterminer)
|
||||
{{else}}à {{../diffLibre }}
|
||||
{{/if}}
|
||||
{{#if esquive.nbUsage}}(Utilisations : {{esquive.nbUsage}}){{/if}}
|
||||
</a>
|
||||
<br>
|
||||
{{else}}
|
||||
{{#each armes as |arme key|}}
|
||||
<a class='chat-card-button button-parade'
|
||||
data-attackerId='{{../attackerId}}' data-defenderTokenId='{{../defenderToken.id}}' data-attackerTokenId='{{../attackerToken.id}}'
|
||||
data-armeid='{{arme._id}}'>
|
||||
Parer avec {{arme.name}}
|
||||
{{#if (or (eq ../attaqueCategorie 'tir') (eq ../attaqueCategorie 'lancer'))}}
|
||||
(difficulté à déterminer)
|
||||
{{else}}à {{../diffLibre }}
|
||||
{{/if}}
|
||||
{{#if (eq arme.typeParade 'sign')}}
|
||||
<span class="rdd-diviseur">×½</span>
|
||||
{{/if}}
|
||||
{{#if arme.nbUsage}}(Utilisations : {{arme.nbUsage}}){{/if}}
|
||||
</a>
|
||||
<br>
|
||||
{{/each}}
|
||||
{{#if mainsNues}}
|
||||
<a class='chat-card-button button-parade'
|
||||
data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}'
|
||||
data-armeid='{{arme._id}}' data-competence='{{arme.system.competence}}'>
|
||||
Parer à mains nues à {{diffLibre}}{{#if arme.nbUsage}} (Utilisations : {{arme.nbUsage}}){{/if}}
|
||||
</a>
|
||||
<br>
|
||||
{{/if}}
|
||||
{{#if (ne attaqueCategorie 'tir')}}
|
||||
{{#each esquives as |esquive key|}}
|
||||
<a class='chat-card-button button-esquive'
|
||||
data-attackerId='{{../attackerId}}' data-defenderTokenId='{{../defenderToken.id}}' data-attackerTokenId='{{../attackerToken.id}}'
|
||||
data-compid='{{esquive._id}}' data-competence='{{esquive.name}}'>
|
||||
{{esquive.name}}
|
||||
{{#if (or (eq ../attaqueCategorie 'tir') (eq ../attaqueCategorie 'lancer'))}}
|
||||
(difficulté à déterminer)
|
||||
{{else}}à {{../diffLibre }}
|
||||
{{/if}}
|
||||
{{#if esquive.nbUsage}}(Utilisations : {{esquive.nbUsage}}){{/if}}
|
||||
</a>
|
||||
<br>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
<a class='chat-card-button encaisser-button'
|
||||
<a class='chat-card-button button-encaisser'
|
||||
data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}'>
|
||||
Encaisser à {{plusMoins dmg.total}}
|
||||
{{#if (eq dmg.mortalite 'non-mortel')~}}
|
||||
|
@@ -2,13 +2,12 @@
|
||||
<span {{#if ajustements}}class="tooltip-overflow tooltip-dotted" {{/if}}>
|
||||
<span>
|
||||
<span>{{rolled.caracValue}} à {{plusMoins rolled.finalLevel}}</span>
|
||||
{{#if ajustements}}
|
||||
{{/if}}
|
||||
{{log this}}
|
||||
{{#if rolled.factorHtml}}<span class="rdd-diviseur">×{{{rolled.factorHtml}}}</span>{{/if}}
|
||||
{{#if (and rolled.factorHtml (gt rolled.factorHtml 1))}}
|
||||
<span class="rdd-diviseur">×{{{rolled.factorHtml}}}</span>
|
||||
<span>= {{rolled.score}}%</span>
|
||||
<span class="rdd-diviseur">×{{{rolled.factorHtml}}}</span>
|
||||
{{else}}
|
||||
<span>= {{rolled.score}}%</span>
|
||||
{{#if rolled.factorHtml}}
|
||||
<span class="rdd-diviseur">×{{{rolled.factorHtml}}}</span>
|
||||
{{/if}}
|
||||
</span>
|
||||
<div class="tooltiptext ttt-ajustements">
|
||||
|
@@ -37,8 +37,8 @@
|
||||
{{#if encaissement.dmg.dmgSurprise}}
|
||||
<div>+dom surprise: {{plusMoins encaissement.dmg.dmgSurprise}}</div>
|
||||
{{/if}}
|
||||
{{#if encaissement.dmg.bonusDegatsDiffLibre}}
|
||||
<div>+dom attaque: {{plusMoins encaissement.dmg.bonusDegatsDiffLibre}}</div>
|
||||
{{#if encaissement.dmg.dmgDiffLibre}}
|
||||
<div>+dom attaque: {{plusMoins encaissement.dmg.dmgDiffLibre}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</span>
|
||||
|
@@ -15,7 +15,7 @@
|
||||
{{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.hbs"}}
|
||||
{{#if options.isOwned}}
|
||||
<div class="flexcol">
|
||||
<ul class="item-list alterne-list">
|
||||
<ul class="item-list alterne-list liste-equipement">
|
||||
<li class="competence-header flexrow">
|
||||
<span class="equipement-nom">Nom</span>
|
||||
<span class="equipement-detail">Q.</span>
|
||||
|
0
templates/roll/result/chat-attaque.hbs
Normal file
0
templates/roll/result/chat-attaque.hbs
Normal file
0
templates/roll/result/chat-competence.hbs
Normal file
0
templates/roll/result/chat-competence.hbs
Normal file
53
templates/roll/result/chat-defense.hbs
Normal file
53
templates/roll/result/chat-defense.hbs
Normal file
@@ -0,0 +1,53 @@
|
||||
|
||||
{{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>
|
0
templates/roll/result/chat-jeu.hbs
Normal file
0
templates/roll/result/chat-jeu.hbs
Normal file
0
templates/roll/result/chat-meditation.hbs
Normal file
0
templates/roll/result/chat-meditation.hbs
Normal file
30
templates/roll/result/chat-oeuvre.hbs
Normal file
30
templates/roll/result/chat-oeuvre.hbs
Normal file
@@ -0,0 +1,30 @@
|
||||
{{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>
|
0
templates/roll/result/chat-sort.hbs
Normal file
0
templates/roll/result/chat-sort.hbs
Normal file
0
templates/roll/result/chat-tache.hbs
Normal file
0
templates/roll/result/chat-tache.hbs
Normal file
22
templates/roll/result/partial-appel-chance.hbs
Normal file
22
templates/roll/result/partial-appel-chance.hbs
Normal file
@@ -0,0 +1,22 @@
|
||||
{{#unless type.retry}}
|
||||
{{#if show.chance}}
|
||||
<a class='appel-chance'
|
||||
data-actorId='{{ids.actorId}}'
|
||||
data-actorTokenId='{{ids.actorTokenId}}'
|
||||
data-opponentId='{{ids.opponentId}}'
|
||||
data-opponentTokenId='{{ids.opponentTokenId}}'
|
||||
data-tooltip="Appel à la chance">
|
||||
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/chance.svg"/>
|
||||
</a>
|
||||
{{#if (gt active.actor.system.compteurs.destinee.value 0)}}
|
||||
<a class='appel-destinee'
|
||||
data-actorId='{{ids.actorId}}'
|
||||
data-actorTokenId='{{ids.actorTokenId}}'
|
||||
data-opponentId='{{ids.opponentId}}'
|
||||
data-opponentTokenId='{{ids.opponentTokenId}}'
|
||||
data-tooltip="Utiliser la destinée">
|
||||
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/destinee.svg"/>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/unless}}
|
15
templates/roll/result/partial-encaissement.hbs
Normal file
15
templates/roll/result/partial-encaissement.hbs
Normal file
@@ -0,0 +1,15 @@
|
||||
{{#if show.encaissement}}
|
||||
{{#if done.encaissement}}
|
||||
<span class='chat-card-info'>
|
||||
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/encaisser.svg"/>
|
||||
{{active.name}} a encaissé
|
||||
</span>
|
||||
{{else}}
|
||||
<a class='chat-card-button encaissement'
|
||||
data-tooltip="Encaisser à {{plusMoins attackerRoll.dmg.total}} {{#if (eq attackerRoll.dmg.mortalite 'non-mortel')~}}(non-mortel){{/if}}"
|
||||
>
|
||||
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/encaisser.svg"/> Encaisser à {{plusMoins attackerRoll.dmg.total}}
|
||||
{{#if (eq attackerRoll.dmg.mortalite 'non-mortel')~}}(non-mortel){{/if}}
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user