Gestion des signes draconiques #455

Closed
vincent.vandeme wants to merge 233 commits from v1.4-signes-draconiques into master
243 changed files with 7077 additions and 3919 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
.vscode/settings.json .vscode/settings.json
.idea
todo.txt todo.txt
todo.md todo.md
/.vscode

61
dev-notes.md Normal file
View File

@ -0,0 +1,61 @@
# Actor notes
> The Actor#getData default implementation gives you the following for use in sheet rendering:
```
actor -> the Actor instance
data -> a cloned copy of Actor#data
items -> a cloned copy of Actor#data#items
effects -> a cloned copy of Actor#data#effects
```
> if all you need is a safe copy of `Actor#data`, you'll be much better off by simply defining your own function and avoiding all the wasted work that the parent class does which will slow down your sheet
```js
getData(options) {
return {
data: foundry.utils.deepClone(this.object.data)
}
}
```
who knows, maybe you don't even need to copy your actor data, skip the copy and it's even faster:
```js
getData(options) {
return {
data: this.object.data
}
}
```
Atropos19/02/2021
There are two recommended ways to create owned items in 0.8.0:
```js
await Item.create(itemData, {parent: actor});
await actor.createEmbeddedDocuments("Item", itemDataArray);
```
You can update an embedded item in one of two ways:
```js
//Method 1:
const item = actor.items.get(itemId);
item.update(data);
//Method 2:
actor.updateEmbeddedDocuments("Item", [{_id: itemId, ...}]);
```
I noticed adding an ActiveEffect to an actor in code using
```js
this.createEmbeddedDocuments('ActiveEffect', [effet], options);
this.applyActiveEffects();
```
Atropos — Aujourdhui à 14:42
Two notes on this:
1. You don't actually need to call this.applyActiveEffects() because this will happen automatically whenever an effect is created/updated/deleted
2. If you want to suppress the automatic display of the sheet for the newly created document, you can pass options.renderSheet = false as part of your options object

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
icons/creatures/dong_t.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
icons/heures/de-heures.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
icons/heures/hd01.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
icons/heures/hd02.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
icons/heures/hd03.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
icons/heures/hd04.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
icons/heures/hd05.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
icons/heures/hd06.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
icons/heures/hd07.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
icons/heures/hd08.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
icons/heures/hd09.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
icons/heures/hd10.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
icons/heures/hd11.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
icons/heures/hd12.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -1,130 +1,103 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="utf-8"?>
<svg <!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
xmlns:dc="http://purl.org/dc/elements/1.1/" <svg version="1.1"
xmlns:cc="http://creativecommons.org/ns#" id="Capa_1" inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)" sodipodi:docname="gift.svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="512px" height="512px"
xmlns:svg="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
xmlns="http://www.w3.org/2000/svg" <style type="text/css">
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" .st0{fill:#FFFFFF;}
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" </style>
version="1.1" <sodipodi:namedview bordercolor="#666666" borderopacity="1" gridtolerance="10" guidetolerance="10" id="namedview47" inkscape:current-layer="g14" inkscape:cx="64" inkscape:cy="163.34211" inkscape:document-rotation="0" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-height="2066" inkscape:window-maximized="1" inkscape:window-width="3840" inkscape:window-x="-11" inkscape:window-y="-11" inkscape:zoom="2.415894" objecttolerance="10" pagecolor="#ffffff" showgrid="false">
id="Capa_1" </sodipodi:namedview>
x="0px" <g id="g14" transform="matrix(5.7,0,0,5.7,1.6591,1.6521435)">
y="0px" <g id="g24-9" transform="matrix(0.1754386,0,0,0.1754386,3.2674006,3.2686582)">
width="512" <path id="path2" class="st0" d="M81.2,212.4c-9.9,13.1-19.3,25.5-8.3,47.1c5,9.7,18.1,11.8,28.3,11.8c20.9,0,45.1-8.1,63-19.2
height="512" c-3-3.7-6.1-8.2-6.1-13.9c0-6.6,4.1-11.6,7.5-15.6c1.6-1.9,3.4-4.1,3.9-5.6c0.5-1.6,0.4-4.4,0.2-7.2c-0.3-5.1-0.7-11.5,3.1-16.6
viewBox="0 0 512 512" c2.7-3.6,6.5-5.5,10.3-6.8c-3.6-8.1-8.4-16.5-14.2-24.5c-14.9-20.5-33-33.8-46.1-33.8c-2.8,0-5.4,0.6-7.8,1.8
xml:space="preserve" c-21.9,11.1-21.4,26.6-20.9,43c0.2,7.4,0.4,14.3-1.6,20.6C90.3,200.4,85.9,206.2,81.2,212.4L81.2,212.4z"/>
sodipodi:docname="gift.svg" <path id="path4" class="st0" d="M464.1,203.8c-7.6-14.8-27-17.9-41.9-17.9c-9.4,0-19.3,1.2-29.2,3.3c1.6,2.6,3.8,5.4,6,8.2
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"><metadata c10.5,13.6,24.9,32.3,9.8,62c-5.7,11.3-17.5,17.8-34.1,19.1c4,3,7.5,6.3,10.4,9.6c7.7,9,11,18.9,9.4,28.7
id="metadata51"><rdf:RDF><cc:Work c-5.2,32.5-27.7,39.4-44.1,44.4c-2.6,0.8-5.2,1.6-7.5,2.4c17.1,17.5,35,27.8,49.4,27.8c4.4,0,8.5-1,12.2-2.9
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type c32.1-16.4,31.4-40,30.6-62.8c-0.3-10-0.6-19.5,2.1-27.8c2.9-9,8.9-17,15.3-25.5C466.7,253.5,480.3,235.5,464.1,203.8L464.1,203.8
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs z"/>
id="defs49" /><sodipodi:namedview <path id="path6" class="st0" d="M270.4,394.7c2.9,0.5,5.6,0.7,8.2,0.7c18.2,0,25.9-11.3,34-23.2c4.1-6.1,8.1-11.8,13.4-15.7
pagecolor="#ffffff" c5.8-4.2,12.8-6.3,20.2-8.6c15.7-4.8,30.6-9.3,34.4-33.2c0.9-5.6-1.2-11.5-6.3-17.4c-8.1-9.5-23.1-18-40-23.7
bordercolor="#666666" c-1.9-0.5-3.7-1.1-5.6-1.7c-9.6-2.8-19.7-4.6-29.2-5c0.3,5,0.5,11.2-3.1,16.2c-3.8,5.2-10,6.8-14.9,8.1c-2.6,0.7-5.3,1.4-6.7,2.4
borderopacity="1" c-1.3,0.9-2.8,3.3-4.2,5.5c-2.8,4.4-6.2,9.8-12.4,11.8c-1.5,0.5-3.1,0.7-4.8,0.7c-1.8,0-3.6-0.3-5.4-0.8
objecttolerance="10" c-3.4,17.1-3.5,37,0.6,54.3C251.2,375.3,257.2,392.6,270.4,394.7L270.4,394.7z"/>
gridtolerance="10" <path id="path8" class="st0" d="M126.4,366c-16.5-4.8-39.1-11.4-44.4-44.4c-1.5-9.7,1.7-19.6,9.4-28.7c2.3-2.6,4.9-5.2,7.9-7.7
guidetolerance="10" c-19.2-0.4-32.7-7.1-38.9-19.4c-15-29.4-0.8-48.1,9.6-61.9c1.5-1.9,2.9-3.8,4.2-5.7c-8.4-1.5-16.8-2.4-24.8-2.4
inkscape:pageopacity="0" c-15.1,0-34.6,3.1-42.2,18c-16.3,32.2-1.9,50.8,12.1,68.8c6.2,7.9,12,15.4,14.7,23.7c2.9,9,2.8,19,2.6,29.6
inkscape:pageshadow="2" c-0.4,23.9-0.8,46.4,30.9,62.5c3.7,1.9,7.7,2.8,12.1,2.8c15.8,0,35.7-12.3,54.2-33.1C131.6,367.5,129,366.8,126.4,366L126.4,366z"
inkscape:window-width="3840" />
inkscape:window-height="2066" <path id="path10" class="st0" d="M276.2,62.2c12.8,0,24.2,5.2,35,16c9.1,9.1,11.6,22.9,7.4,39.6c9.6-6.5,19.2-10,27.9-10
id="namedview47" c5,0,9.8,1.1,14.1,3.3c29.4,15,28.9,38.5,28.6,55.7c0,2-0.1,4-0.1,5.9c13.7-6.9,25.3-15.1,32.9-23.9c7.6-8.9,10.8-17.9,9.4-26.6
showgrid="false" C425.6,86.6,403,80,381.1,73.7c-9.6-2.8-18.7-5.4-25.8-10.5c-7.7-5.6-13.4-13.8-19.5-22.4C324.3,24.3,312.4,7.3,286,7.3
inkscape:zoom="2.415894" c-3.7,0-7.8,0.3-11.9,1C254,11.5,245,37,241.5,51.8c-1.5,6.2-2.6,12.9-3.3,19.9c3.3-0.7,7-2,10.9-3.4
inkscape:cx="64" C257.1,65.4,266.1,62.2,276.2,62.2z"/>
inkscape:cy="163.34211" <path id="path12" class="st0" d="M80.3,180.7c0-2.3,0-4.7-0.1-7.3c-0.5-17.2-1.2-40.8,28.6-55.9c4.3-2.2,9.1-3.3,14.1-3.3
inkscape:window-x="-11" c8.3,0,17.5,3.2,26.6,9.1c-6.3-19.2-4.4-35.1,5.7-45.2c10.7-10.7,22.1-15.9,34.9-15.9c9.9,0,18.9,3.1,26.9,5.9
inkscape:window-y="-11" c1.4,0.5,2.8,1,4.2,1.4c-0.7-5-1.6-9.8-2.7-14.4c-3.6-14.9-12.6-40.2-32.7-43.4c-4.1-0.6-8.1-1-11.8-1
inkscape:window-maximized="1" c-26.9,0-38.6,17.2-49.9,33.7c-5.6,8.3-11,16.2-18,21.3c-7.7,5.6-17.2,8.5-27.4,11.6c-22.8,7-44.4,13.6-49.9,48.7
inkscape:current-layer="g14" c-1.4,8.7,1.8,17.6,9.4,26.5C47.4,163.4,62.6,173.1,80.3,180.7z"/>
inkscape:document-rotation="0" /> <path id="path14" class="st0" d="M328.2,374.4c-1.3,1.8-2.6,3.7-3.9,5.6c-8.4,12.4-20,29.3-45.6,29.3c-3.3,0-6.8-0.3-10.4-0.9
<g c-12.7-2-22.8-11.6-29.1-27.5c-6.2,18.7-17,30-30.9,32.2c-3.6,0.6-7.1,0.9-10.3,0.9c-25.2,0-36.5-16.1-45.5-29.1
id="g14" c-1.6-2.2-3.1-4.4-4.6-6.4c-2.5,4.7-4.8,9.3-6.6,13.9c-5.8,14.1-13.4,40,0.9,54.3c11.9,11.8,23.6,17.3,36.9,17.3
transform="matrix(5.7,0,0,5.7,1.6591,1.6521435)"> c11.2,0,21.9-3.9,32.2-7.6c9.4-3.4,18.4-6.6,27.1-6.6c9.5,0,19,3.2,29,6.7c10.4,3.6,21.1,7.2,32.1,7.2h0
c13.4,0,25.1-5.5,36.9-17.4c14.3-14.4,6.6-40.1,0.8-54.2C334.6,386.4,331.6,380.4,328.2,374.4L328.2,374.4z"/>
<g <path id="path16" class="st0" d="M190.1,76.3c-9,0-16.9,3.7-25,11.8c-9.5,9.5-4.2,27-0.2,36.7c7.7,18.6,21.7,36.5,36.3,48.6
id="g24-9" c2.4-3.3,5.4-6.5,9.8-7.9c1.5-0.5,3.1-0.7,4.8-0.7c4.2,0,8.2,1.6,11.8,2.9c2.6,1,5.3,2.1,7.1,2.1s4.5-1.1,7.1-2.1
transform="matrix(0.1754386,0,0,0.1754386,3.2674006,3.2686582)" c3.5-1.4,7.5-2.9,11.8-2.9c1.7,0,3.3,0.2,4.8,0.7c3.7,1.2,6.4,3.7,8.6,6.4c14-12,27.1-29.3,34.5-47.1c4-9.6,9.3-27.2-0.2-36.7
style="fill:#ffffff;stroke:none"><path c-8.1-8.1-16.1-11.9-25.1-11.9c-7.6,0-15.1,2.7-22.3,5.3c-6.9,2.5-13.5,4.8-20,4.8c-7.1,0-14-2.4-21.4-4.9
d="m 81.245,212.419 c -9.902,13.127 -19.256,25.526 -8.273,47.079 4.957,9.729 18.132,11.771 28.311,11.771 20.904,0 45.125,-8.057 63.033,-19.182 -2.994,-3.719 -6.111,-8.237 -6.111,-13.949 0,-6.576 4.131,-11.571 7.451,-15.585 1.601,-1.936 3.415,-4.129 3.882,-5.569 0.523,-1.607 0.357,-4.439 0.197,-7.178 -0.299,-5.108 -0.67,-11.466 3.069,-16.605 2.653,-3.644 6.503,-5.517 10.286,-6.759 -3.608,-8.125 -8.398,-16.488 -14.204,-24.48 -14.902,-20.512 -32.983,-33.767 -46.06,-33.767 -2.845,0 -5.39,0.592 -7.78,1.81 -21.868,11.143 -21.404,26.636 -20.912,43.039 0.22,7.359 0.429,14.31 -1.603,20.561 -2.198,6.767 -6.612,12.619 -11.286,18.814 z" C205.1,78.9,197.6,76.3,190.1,76.3z"/>
id="path2" <path id="path18" class="st0" d="M396.3,253.1c11.1-21.9,1.7-34.1-8.4-47.1c-4.5-5.8-8.8-11.3-10.8-17.6
style="fill:#ffffff;stroke:none" /><path c-2.2-6.8-2.1-14.1-1.9-21.9c0.3-16.4,0.6-32-21-43c-2.4-1.2-4.9-1.8-7.8-1.8c-13.1,0-31.2,13.3-46.1,33.8
d="m 464.076,203.816 c -7.567,-14.789 -26.952,-17.893 -41.88,-17.893 -9.41,0 -19.295,1.161 -29.221,3.252 1.645,2.602 3.775,5.369 5.992,8.235 10.528,13.614 24.948,32.259 9.778,62.032 -5.735,11.255 -17.472,17.797 -34.132,19.144 4.004,3.046 7.514,6.264 10.369,9.608 7.716,9.035 10.98,18.948 9.44,28.668 -5.153,32.537 -27.667,39.408 -44.107,44.425 -2.622,0.8 -5.172,1.586 -7.547,2.43 17.125,17.508 34.971,27.756 49.438,27.756 4.384,0 8.483,-0.96 12.185,-2.855 32.102,-16.428 31.354,-39.981 30.631,-62.76 -0.318,-10.034 -0.619,-19.512 2.054,-27.791 2.912,-9.018 8.93,-17.024 15.301,-25.501 14.344,-19.083 27.892,-37.108 11.699,-68.75 z" c-7.2,9.9-12.8,20.3-16.5,30.2c4.5,1.2,9.5,3.1,12.7,7.5c3.7,5.1,3.4,11.5,3.1,16.6c-0.2,2.7-0.3,5.6,0.2,7.2
id="path4" c0.5,1.4,2.3,3.6,3.9,5.6c3.3,4,7.5,9,7.5,15.6c0,3.6-1.2,6.7-2.9,9.5c7,4,14.8,7.6,22.9,10.4c3,0.8,6,1.8,8.9,2.8
style="fill:#ffffff;stroke:none" /><path c9.4,2.6,19,4.1,28,4.1C378.1,264.9,391.3,262.8,396.3,253.1L396.3,253.1z"/>
d="m 270.444,394.702 c 2.878,0.456 5.642,0.687 8.214,0.687 18.176,0 25.863,-11.274 34.001,-23.211 4.148,-6.084 8.066,-11.83 13.384,-15.693 5.755,-4.182 12.766,-6.321 20.188,-8.587 15.727,-4.8 30.581,-9.333 34.364,-33.225 0.893,-5.63 -1.213,-11.479 -6.258,-17.386 -8.141,-9.532 -23.127,-18.049 -39.956,-23.652 -1.862,-0.538 -3.721,-1.116 -5.575,-1.729 -9.632,-2.772 -19.668,-4.561 -29.237,-5.027 0.292,5.036 0.549,11.19 -3.092,16.193 -3.771,5.18 -9.963,6.789 -14.938,8.081 -2.629,0.683 -5.348,1.389 -6.67,2.351 -1.28,0.933 -2.769,3.273 -4.207,5.537 -2.776,4.368 -6.232,9.804 -12.397,11.806 -1.511,0.491 -3.127,0.739 -4.804,0.739 -1.835,0 -3.626,-0.305 -5.359,-0.754 -3.383,17.09 -3.525,36.966 0.635,54.293 2.436,10.148 8.497,27.485 21.707,29.577 z" <path id="path20" class="st0" d="M95.9,319.4c3.8,24.2,18.7,28.6,34.5,33.2c7.1,2.1,13.7,4,19.1,7.9c5.8,4.2,10,10.2,14.4,16.5
id="path6" c8.3,11.9,16.2,23.1,34.1,23.1c2.6,0,5.3-0.2,8.2-0.7c13.2-2.1,19.3-19.4,21.7-29.6c4.7-19.6,3.9-42.5-0.9-60.9
style="fill:#ffffff;stroke:none" /><path c-3.4,1.3-7.1,2.7-11.1,2.7c-1.7,0-3.3-0.2-4.8-0.7c-6.2-2-9.6-7.4-12.4-11.8c-1.4-2.3-2.9-4.6-4.2-5.5c-1.3-1-4-1.7-6.7-2.4
d="m 126.439,366.003 c -16.52,-4.826 -39.144,-11.435 -44.37,-44.438 -1.539,-9.719 1.725,-19.632 9.44,-28.667 2.257,-2.643 4.924,-5.206 7.915,-7.669 -19.207,-0.406 -32.657,-7.071 -38.927,-19.376 -14.955,-29.353 -0.779,-48.145 9.572,-61.866 1.457,-1.931 2.882,-3.822 4.177,-5.669 -8.438,-1.537 -16.798,-2.384 -24.81,-2.384 -15.076,0 -34.636,3.13 -42.2,18.042 -16.315,32.161 -1.866,50.776 12.108,68.778 6.156,7.931 11.971,15.422 14.674,23.692 2.944,9.006 2.782,19.021 2.61,29.623 -0.386,23.87 -0.751,46.416 30.949,62.497 3.678,1.866 7.743,2.811 12.085,2.811 15.828,0 35.7,-12.34 54.219,-33.068 -2.312,-0.8 -4.839,-1.546 -7.442,-2.306 z" c-5-1.3-11.2-2.9-14.9-8.1c-2.4-3.3-3.1-7.2-3.2-10.9c-26.6,3-55,15.2-67.4,29.8C97.1,307.9,95,313.7,95.9,319.4L95.9,319.4z"/>
id="path8" <path id="path22" class="st0" d="M246.8,295.6c2.5,1,5.1,2,6.7,2c0.2,0,0.4,0,0.5-0.1c1.4-0.4,3.4-3.7,4.9-6
style="fill:#ffffff;stroke:none" /><path c2-3.2,4.4-6.8,7.8-9.3c3.5-2.5,7.7-3.6,11.4-4.6c2.7-0.7,6.3-1.6,7.1-2.8c0.8-1.1,0.6-4.8,0.4-7.5c-0.2-3.8-0.5-8.2,0.9-12.3
d="m 276.172,62.189 c 12.786,0 24.223,5.22 34.962,15.96 9.115,9.115 11.603,22.92 7.36,39.616 9.602,-6.462 19.178,-9.98 27.922,-9.98 5.036,0 9.792,1.123 14.137,3.337 29.352,14.955 28.93,38.491 28.62,55.676 -0.036,2.032 -0.067,4.02 -0.056,5.943 13.727,-6.889 25.322,-15.114 32.853,-23.947 7.611,-8.928 10.762,-17.875 9.364,-26.592 C 425.63,86.594 402.997,80.027 381.11,73.676 371.468,70.879 362.361,68.236 355.314,63.135 347.636,57.578 341.881,49.38 335.789,40.701 324.269,24.291 312.358,7.323 285.965,7.323 c -3.748,0 -7.768,0.339 -11.947,1.009 -20.054,3.212 -28.987,28.625 -32.527,43.488 -1.487,6.242 -2.569,12.945 -3.271,19.898 3.292,-0.724 7.018,-2.048 10.899,-3.439 7.965,-2.855 16.995,-6.09 27.053,-6.09 z" c1.3-4,4-7.3,6.4-10.2c1.9-2.3,4.2-5.1,4.2-6.7c0-1.5-2.4-4.4-4.2-6.7c-2.4-2.9-5.1-6.2-6.4-10.2c-1.3-4.1-1.1-8.5-0.9-12.3
id="path10" c0.2-2.7,0.4-6.5-0.4-7.5c-0.8-1.1-4.5-2.1-7.1-2.8c-3.7-1-7.9-2.1-11.4-4.6c-3.4-2.5-5.7-6.1-7.8-9.3c-1.5-2.3-3.5-5.6-4.9-6
style="fill:#ffffff;stroke:none" /><path c-0.1,0-0.3-0.1-0.5-0.1c-1.6,0-4.2,1-6.7,2c-3.6,1.4-7.7,3-12.2,3s-8.5-1.6-12.2-3c-2.5-1-5.1-2-6.7-2c-0.2,0-0.4,0-0.5,0.1
d="m 80.254,180.726 c 0.028,-2.296 -0.039,-4.745 -0.114,-7.261 -0.516,-17.203 -1.222,-40.762 28.551,-55.932 4.345,-2.214 9.101,-3.336 14.136,-3.336 8.349,0 17.457,3.203 26.621,9.117 -6.331,-19.186 -4.373,-35.058 5.734,-45.165 10.691,-10.692 22.104,-15.89 34.887,-15.89 9.877,0 18.926,3.121 26.909,5.875 1.419,0.49 2.817,0.97 4.191,1.424 -0.685,-4.98 -1.561,-9.809 -2.666,-14.377 -3.594,-14.851 -12.618,-40.235 -32.683,-43.376 -4.124,-0.646 -8.094,-0.973 -11.801,-0.973 -26.95,0 -38.601,17.153 -49.868,33.742 -5.641,8.306 -10.969,16.151 -17.999,21.277 -7.655,5.583 -17.23,8.524 -27.367,11.638 -22.821,7.009 -44.376,13.629 -49.874,48.746 -1.361,8.696 1.798,17.605 9.392,26.48 9.129,10.667 24.272,20.436 41.951,28.011 z" c-1.4,0.4-3.4,3.7-4.9,6c-2,3.2-4.4,6.9-7.8,9.3c-3.5,2.5-7.7,3.6-11.4,4.6c-2.7,0.7-6.3,1.6-7.1,2.8c-0.8,1.1-0.6,4.8-0.4,7.5
id="path12" c0.2,3.8,0.5,8.2-0.9,12.3c-1.3,4-4,7.3-6.4,10.2c-1.9,2.3-4.2,5.1-4.2,6.7c0,1.5,2.4,4.4,4.2,6.7c2.4,2.9,5.1,6.2,6.4,10.2
style="fill:#ffffff;stroke:none" /><path c1.3,4.1,1.1,8.5,0.9,12.3c-0.2,2.7-0.4,6.5,0.4,7.5c0.8,1.1,4.5,2.1,7.1,2.8c3.7,1,7.9,2.1,11.4,4.6c3.4,2.5,5.7,6.1,7.8,9.3
d="m 328.161,374.443 c -1.295,1.753 -2.6,3.664 -3.935,5.621 -8.438,12.375 -19.993,29.324 -45.568,29.324 -3.304,0 -6.804,-0.289 -10.403,-0.859 -12.671,-2.006 -22.761,-11.63 -29.146,-27.494 -6.21,18.666 -16.992,30 -30.871,32.198 -3.581,0.567 -7.063,0.854 -10.349,0.854 -25.198,0 -36.474,-16.121 -45.533,-29.075 -1.561,-2.232 -3.085,-4.399 -4.611,-6.387 -2.519,4.654 -4.752,9.299 -6.633,13.862 -5.821,14.126 -13.439,39.965 0.946,54.3 11.86,11.818 23.598,17.323 36.938,17.323 11.172,0 21.87,-3.855 32.217,-7.584 9.445,-3.404 18.367,-6.619 27.066,-6.634 9.527,0 18.977,3.24 28.98,6.671 10.371,3.556 21.096,7.234 32.052,7.234 h 0.005 c 13.408,-0.002 25.147,-5.516 36.943,-17.354 14.313,-14.363 6.645,-40.121 0.8,-54.197 -2.432,-5.852 -5.439,-11.836 -8.898,-17.803 z" c1.5,2.3,3.5,5.6,4.9,6c0.1,0,0.3,0.1,0.5,0.1c1.6,0,4.2-1,6.7-2c3.6-1.4,7.7-3,12.2-3S243.2,294.2,246.8,295.6L246.8,295.6z"/>
id="path14" </g>
style="fill:#ffffff;stroke:none" /><path </g>
d="m 190.069,76.259 c -9.005,0 -16.944,3.746 -24.987,11.789 -9.459,9.458 -4.171,27.047 -0.177,36.69 7.686,18.555 21.693,36.525 36.309,48.605 2.38,-3.296 5.398,-6.483 9.806,-7.914 1.511,-0.491 3.127,-0.739 4.805,-0.739 4.22,0 8.227,1.567 11.763,2.949 2.6,1.016 5.287,2.067 7.057,2.067 1.77,0 4.457,-1.051 7.057,-2.067 3.535,-1.382 7.543,-2.948 11.762,-2.948 1.678,0 3.294,0.249 4.805,0.739 3.715,1.206 6.442,3.662 8.633,6.377 13.957,-12.04 27.143,-29.278 34.512,-47.07 3.994,-9.643 9.282,-27.231 -0.176,-36.69 -8.092,-8.091 -16.055,-11.859 -25.063,-11.859 -7.626,0 -15.102,2.679 -22.331,5.27 -6.931,2.484 -13.477,4.83 -20.049,4.83 -7.115,0 -14.044,-2.39 -21.379,-4.92 -7.286,-2.512 -14.816,-5.109 -22.347,-5.109 z" <g id="g16">
id="path16" </g>
style="fill:#ffffff;stroke:none" /><path <g id="g18">
d="m 396.271,253.086 c 11.144,-21.87 1.661,-34.13 -8.379,-47.111 -4.504,-5.824 -8.758,-11.324 -10.789,-17.574 -2.199,-6.768 -2.067,-14.096 -1.928,-21.855 0.296,-16.44 0.575,-31.969 -20.978,-42.951 -2.392,-1.218 -4.936,-1.811 -7.781,-1.811 -13.076,0 -31.153,13.253 -46.055,33.763 -7.177,9.878 -12.801,20.322 -16.549,30.183 4.48,1.242 9.45,3.059 12.663,7.474 3.74,5.139 3.368,11.496 3.069,16.604 -0.16,2.739 -0.326,5.571 0.196,7.178 0.467,1.44 2.281,3.633 3.882,5.568 3.319,4.014 7.45,9.008 7.45,15.583 0,3.601 -1.241,6.724 -2.907,9.475 6.998,4.038 14.811,7.587 22.921,10.41 3.011,0.836 5.989,1.759 8.917,2.766 9.424,2.568 18.994,4.068 27.956,4.068 10.181,0.001 23.356,-2.041 28.312,-11.77 z" </g>
id="path18" <g id="g20">
style="fill:#ffffff;stroke:none" /><path </g>
d="m 95.897,319.376 c 3.839,24.242 18.717,28.588 34.468,33.189 7.066,2.064 13.742,4.015 19.059,7.877 5.757,4.182 9.957,10.189 14.404,16.547 8.308,11.878 16.155,23.098 34.061,23.098 2.555,0 5.299,-0.229 8.159,-0.683 13.211,-2.092 19.271,-19.429 21.708,-29.577 4.71,-19.62 3.901,-42.504 -0.881,-60.914 -3.359,1.307 -7.109,2.672 -11.051,2.672 -1.678,0 -3.294,-0.249 -4.805,-0.739 -6.165,-2.001 -9.621,-7.438 -12.398,-11.805 -1.439,-2.264 -2.928,-4.605 -4.208,-5.538 -1.322,-0.962 -4.041,-1.668 -6.67,-2.351 -4.976,-1.292 -11.168,-2.9 -14.938,-8.08 -2.434,-3.342 -3.123,-7.199 -3.229,-10.893 -26.569,3.035 -54.982,15.244 -67.422,29.811 -5.043,5.908 -7.149,11.757 -6.257,17.386 z" <g id="g22">
id="path20" </g>
style="fill:#ffffff;stroke:none" /><path <g id="g24">
d="m 246.796,295.599 c 2.499,0.978 5.084,1.988 6.664,1.988 0.204,0 0.37,-0.019 0.48,-0.055 1.376,-0.447 3.416,-3.657 4.906,-6.001 2.04,-3.21 4.354,-6.849 7.784,-9.346 3.469,-2.525 7.677,-3.618 11.388,-4.583 2.666,-0.692 6.317,-1.641 7.139,-2.768 0.79,-1.086 0.571,-4.821 0.411,-7.548 -0.225,-3.845 -0.48,-8.204 0.856,-12.32 1.292,-3.98 4.011,-7.267 6.41,-10.168 1.889,-2.283 4.238,-5.124 4.238,-6.661 0,-1.536 -2.351,-4.378 -4.238,-6.661 -2.399,-2.9 -5.118,-6.188 -6.41,-10.168 -1.336,-4.115 -1.081,-8.474 -0.856,-12.319 0.16,-2.728 0.379,-6.462 -0.412,-7.549 -0.82,-1.127 -4.471,-2.075 -7.137,-2.768 -3.712,-0.964 -7.918,-2.057 -11.388,-4.583 -3.432,-2.497 -5.745,-6.136 -7.786,-9.347 -1.489,-2.344 -3.529,-5.553 -4.904,-5.999 -0.11,-0.036 -0.276,-0.055 -0.48,-0.055 -1.58,0 -4.165,1.01 -6.665,1.988 -3.63,1.419 -7.745,3.027 -12.153,3.027 -4.408,0 -8.523,-1.609 -12.154,-3.028 -2.5,-0.978 -5.085,-1.988 -6.665,-1.988 -0.204,0 -0.371,0.019 -0.482,0.055 -1.375,0.446 -3.415,3.656 -4.904,5.999 -2.041,3.211 -4.355,6.85 -7.787,9.348 -3.47,2.525 -7.677,3.617 -11.389,4.581 -2.666,0.692 -6.317,1.64 -7.139,2.768 -0.79,1.086 -0.572,4.822 -0.413,7.549 0.225,3.845 0.48,8.203 -0.856,12.319 -1.293,3.98 -4.012,7.267 -6.41,10.167 -1.889,2.284 -4.239,5.126 -4.239,6.662 0,1.537 2.351,4.378 4.239,6.662 2.398,2.9 5.117,6.187 6.41,10.167 1.336,4.115 1.081,8.473 0.856,12.318 -0.159,2.728 -0.377,6.463 0.414,7.55 0.821,1.128 4.472,2.076 7.138,2.768 3.712,0.964 7.918,2.056 11.389,4.581 3.432,2.497 5.745,6.136 7.786,9.347 1.489,2.344 3.53,5.554 4.905,6.001 0.111,0.036 0.277,0.055 0.482,0.055 1.58,0 4.165,-1.011 6.666,-1.988 3.63,-1.419 7.745,-3.028 12.153,-3.028 4.408,0 8.523,1.612 12.153,3.031 z" </g>
id="path22" <g id="g26">
style="fill:#ffffff;stroke:none" /></g></g> </g>
<g <g id="g28">
id="g16"> </g>
</g> <g id="g30">
<g </g>
id="g18"> <g id="g32">
</g> </g>
<g <g id="g34">
id="g20"> </g>
</g> <g id="g36">
<g </g>
id="g22"> <g id="g38">
</g> </g>
<g <g id="g40">
id="g24"> </g>
</g> <g id="g42">
<g </g>
id="g26"> <g id="g44">
</g> </g>
<g </svg>
id="g28">
</g>
<g
id="g30">
</g>
<g
id="g32">
</g>
<g
id="g34">
</g>
<g
id="g36">
</g>
<g
id="g38">
</g>
<g
id="g40">
</g>
<g
id="g42">
</g>
<g
id="g44">
</g>
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

BIN
icons/tmr/gift.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
icons/tmr/pelerin.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
icons/tmr/scroll.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
icons/tmr/wave.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -35,12 +35,10 @@ export class RdDActorCreatureSheet extends RdDActorSheet {
encTotal: await this.actor.computeEncombrementTotalEtMalusArmure(), encTotal: await this.actor.computeEncombrementTotalEtMalusArmure(),
} }
formData.calc.surEncombrementMessage = (formData.data.compteurs.surenc.value < 0) ? "Sur-Encombrement!" : ""; formData.calc.surEncombrementMessage = (formData.data.compteurs.surenc.value < 0) ? "Sur-Encombrement!" : "";
formData.options.isGM = game.user.isGM;
formData.data.competencecreature = formData.itemsByType["competencecreature"];
RdDUtility.filterItemsPerTypeForSheet(formData); RdDUtility.filterItemsPerTypeForSheet(formData);
RdDUtility.buildArbreDeConteneur(this, formData); this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
console.log("Creature : ", this.objetVersConteneur, formData); console.log("Creature : ", this.objetVersConteneur, formData);
@ -72,17 +70,6 @@ export class RdDActorCreatureSheet extends RdDActorSheet {
}); });
} }
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - 192;
sheetBody.css("height", bodyHeight);
return position;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
_updateObject(event, formData) { _updateObject(event, formData) {

View File

@ -5,6 +5,7 @@
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDActorEntiteSheet extends ActorSheet { export class RdDActorEntiteSheet extends ActorSheet {
@ -31,14 +32,27 @@ export class RdDActorEntiteSheet extends ActorSheet {
/* -------------------------------------------- */ /* -------------------------------------------- */
async getData() { async getData() {
let formData = super.getData(); const objectData = Misc.data(this.object);
let formData = {
title: this.title,
id: objectData.id,
type: objectData.type,
img: objectData.img,
name: objectData.name,
// actor: this.object,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
data: foundry.utils.deepClone(Misc.templateData(this.object)),
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
// items: items,
limited: this.object.limited,
options: this.options,
owner: this.document.isOwner,
itemsByType: Misc.classify(this.object.items.map(i => foundry.utils.deepClone(i.data))),
};
formData.itemsByType = Misc.classify(formData.items);
formData.options.isGM = game.user.isGM; formData.options.isGM = game.user.isGM;
RdDUtility.filterItemsPerTypeForSheet(formData);
formData.data.carac.taille.isTaille = true; // To avoid button link;
formData.data.competencecreature = formData.itemsByType["competencecreature"];
return formData; return formData;
@ -57,14 +71,14 @@ export class RdDActorEntiteSheet extends ActorSheet {
// Update Inventory Item // Update Inventory Item
html.find('.item-edit').click(ev => { html.find('.item-edit').click(ev => {
const li = $(ev.currentTarget).parents(".item"); const li = $(ev.currentTarget).parents(".item");
const item = this.actor.getOwnedItem(li.data("itemId")); const item = this.actor.getEmbeddedDocument('Item', li.data("itemId"));
item.sheet.render(true); item.sheet.render(true);
}); });
// Delete Inventory Item // Delete Inventory Item
html.find('.item-delete').click(ev => { html.find('.item-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item"); const li = $(ev.currentTarget).parents(".item");
this.actor.deleteOwnedItem(li.data("itemId")); this.actor.deleteEmbeddedDocuments('Item', [li.data("itemId")]);
li.slideUp(200, () => this.render(false)); li.slideUp(200, () => this.render(false));
}); });
@ -103,7 +117,7 @@ export class RdDActorEntiteSheet extends ActorSheet {
this.render(true); this.render(true);
}); });
html.find('#encaisser-direct').click(ev => { html.find('.encaisser-direct').click(ev => {
this.actor.encaisser(); this.actor.encaisser();
}); });
@ -118,10 +132,12 @@ export class RdDActorEntiteSheet extends ActorSheet {
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
setPosition(options={}) { setPosition(options = {}) {
const position = super.setPosition(options); const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetTabs = this.element.find(".sheet-tabs");
const sheetBody = this.element.find(".sheet-body"); const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - 192; const bodyHeight = position.height - sheetHeader[0].clientHeight - sheetTabs[0].clientHeight;
sheetBody.css("height", bodyHeight); sheetBody.css("height", bodyHeight);
return position; return position;
} }

View File

@ -11,6 +11,9 @@ import { RdDBonus } from "./rdd-bonus.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js"; import { RdDCombatManager } from "./rdd-combat.js";
import { RdDCarac } from "./rdd-carac.js"; import { RdDCarac } from "./rdd-carac.js";
import { RdDItem } from "./item.js";
import { DialogSplitItem } from "./dialog-split-item.js";
import { ReglesOptionelles } from "./regles-optionelles.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDActorSheet extends ActorSheet { export class RdDActorSheet extends ActorSheet {
@ -33,54 +36,45 @@ export class RdDActorSheet extends ActorSheet {
/* -------------------------------------------- */ /* -------------------------------------------- */
async getData() { async getData() {
let formData = super.getData(); const objectData = Misc.data(this.object);
// -------------- version 0.7.9 let formData = {
// let formData = { title: this.title,
// cssClass: this.entity.owner ? "editable" : "locked", id: objectData.id,
// editable: this.isEditable, type: objectData.type,
// entity: duplicate(this.entity.data), img: objectData.img,
// limited: this.entity.limited, name: objectData.name,
// options: this.options, editable: this.isEditable,
// owner: this.entity.owner, cssClass: this.isEditable ? "editable" : "locked",
// title: this.title data: foundry.utils.deepClone(Misc.templateData(this.object)),
// } effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
// // Entity data limited: this.object.limited,
// formData.actor = formData.entity; options: this.options,
// formData.data = formData.entity.data; owner: this.document.isOwner,
itemsByType: Misc.classify(this.object.items.map(i => foundry.utils.deepClone(i.data))),
};
// // Owned items
// formData.items = formData.actor.items;
// formData.items.sort((a, b) => (a.sort || 0) - (b.sort || 0));
formData.itemsByType = Misc.classify(formData.items);
RdDUtility.filterItemsPerTypeForSheet(formData); RdDUtility.filterItemsPerTypeForSheet(formData);
formData.options.isGM = game.user.isGM; formData.options.isGM = game.user.isGM;
// la taille est la taille: on ne peut pas l'utiliser pour un jet if (formData.type == 'creature') return formData; // Shortcut
formData.data.carac.taille.isTaille = true;
if (this.actor.data.type == 'creature') return formData; // Shortcut formData.competenceByCategory = Misc.classify(formData.competences, it => it.data.categorie);
formData.competenceByCategory = Misc.classify(formData.data.competences, it => it.data.categorie);
formData.calc = { formData.calc = {
comptageArchetype: RdDItemCompetence.computeResumeArchetype(formData.data.competences), comptageArchetype: RdDItemCompetence.computeResumeArchetype(formData.competences),
competenceXPTotal: RdDItemCompetence.computeTotalXP(formData.data.competences), competenceXPTotal: RdDItemCompetence.computeTotalXP(formData.competences),
caracTotal: RdDCarac.computeTotal(formData.data.carac, formData.data.beaute), caracTotal: RdDCarac.computeTotal(formData.data.carac, formData.data.beaute),
// Mise à jour de l'encombrement total et du prix de l'équipement // Mise à jour de l'encombrement total et du prix de l'équipement
encTotal: await this.actor.computeEncombrementTotalEtMalusArmure(), encTotal: await this.actor.computeEncombrementTotalEtMalusArmure(),
prixTotalEquipement: await this.actor.computePrixTotalEquipement(), prixTotalEquipement: this.actor.computePrixTotalEquipement(),
surprise: RdDBonus.find(this.actor.getSurprise(false)).descr, surprise: RdDBonus.find(this.actor.getSurprise(false)).descr,
fatigue: { fatigue: RdDUtility.calculFatigueHtml(formData.data.sante.fatigue.value, formData.data.sante.endurance.max),
malus: RdDUtility.calculMalusFatigue(formData.data.sante.fatigue.value, formData.data.sante.endurance.max),
html: "<table class='table-fatigue'>" + RdDUtility.makeHTMLfatigueMatrix(formData.data.sante.fatigue.value, formData.data.sante.endurance.max).html() + "</table>"
},
resumeBlessures: this.actor.computeResumeBlessure(formData.data.blessures), resumeBlessures: this.actor.computeResumeBlessure(formData.data.blessures),
}; };
formData.calc.surEncombrementMessage = (formData.data.compteurs.surenc.value < 0) ? "Sur-Encombrement!" : ""; formData.calc.surEncombrementMessage = (formData.data.compteurs.surenc.value < 0) ? "Sur-Encombrement!" : "";
formData.data.competences.forEach(item => { formData.competences.forEach(item => {
item.visible = !this.options.showCompNiveauBase || !RdDItemCompetence.isNiveauBase(item); item.visible = !this.options.showCompNiveauBase || !RdDItemCompetence.isNiveauBase(item);
RdDItemCompetence.levelUp(item); RdDItemCompetence.levelUp(item);
}); });
@ -91,41 +85,37 @@ export class RdDActorSheet extends ActorSheet {
// toujours avoir une liste d'armes (pour mettre esquive et corps à corps) // toujours avoir une liste d'armes (pour mettre esquive et corps à corps)
formData.data.combat = duplicate(formData.itemsByType.arme ?? []); formData.combat = duplicate(formData.armes ?? []);
RdDItemArme.computeNiveauArmes(formData.data.combat, formData.data.competences); RdDItemArme.computeNiveauArmes(formData.combat, formData.competences);
RdDItemArme.ajoutCorpsACorps(formData.data.combat, formData.data.competences, formData.data.carac ); RdDItemArme.ajoutCorpsACorps(formData.combat, formData.competences, formData.data.carac);
formData.esquive = RdDItemCompetence.getEsquive(formData.data.competences); formData.esquive = RdDItemCompetence.getEsquive(formData.competences);
formData.data.combat = RdDCombatManager.finalizeArmeList(formData.data.combat, formData.itemsByType.competence, formData.data.carac); formData.combat = RdDCombatManager.finalizeArmeList(formData.combat, formData.competences, formData.data.carac);
this.armesList = formData.combat;
this.armesList = formData.data.combat;
// Mise à jour de l'encombrement total et du prix de l'équipement
// Common data // Common data
formData.data.competenceByCategory = formData.competenceByCategory;
formData.data.isGM = game.user.isGM;
formData.ajustementsConditions = CONFIG.RDD.ajustementsConditions; formData.ajustementsConditions = CONFIG.RDD.ajustementsConditions;
formData.difficultesLibres = CONFIG.RDD.difficultesLibres; formData.difficultesLibres = CONFIG.RDD.difficultesLibres;
// low is normal, this the base used to compute the grid.
formData.data.fatigue = {
malus: RdDUtility.calculMalusFatigue(formData.data.sante.fatigue.value, formData.data.sante.endurance.max),
html: "<table class='table-fatigue'>" + RdDUtility.makeHTMLfatigueMatrix(formData.data.sante.fatigue.value, formData.data.sante.endurance.max).html() + "</table>"
}
formData.hautreve = { formData.hautreve = {
sortsReserve: formData.data.reve.reserve.list, sortsReserve: formData.data.reve.reserve.list,
rencontres: duplicate(formData.data.reve.rencontre.list), rencontres: duplicate(formData.data.reve.rencontre.list),
casesTmr: formData.itemsByType.casetmr casesTmr: formData.itemsByType.casetmr,
cacheTMR: this.actor.isTMRCache()
} }
RdDUtility.buildArbreDeConteneur(this, formData); this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
formData.subacteurs = { formData.subacteurs = {
vehicules: this.actor.listeVehicules(), vehicules: this.actor.listeVehicules(),
montures: this.actor.listeMontures(), montures: this.actor.listeMontures(),
suivants: this.actor.listeSuivants() suivants: this.actor.listeSuivants()
} }
if (this.actor.getBestDraconic().data.niveau > -11 && !this.actor.isHautRevant()) {
ui.notifications.error(`${this.actor.name} a des compétences draconiques, mais pas le don de Haut-Rêve!
<br>Ajoutez-lui la tête "Don de Haut-Rêve" pour lui permettre d'utiliser ses compétences et d'accéder aux terres médianes du rêve`);
}
return formData; return formData;
} }
@ -134,30 +124,42 @@ export class RdDActorSheet extends ActorSheet {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async _onDrop(event) { async _onDropActor(event, dragData) {
let toSuper = await RdDUtility.processItemDropEvent(this, event); console.log("DRAG", this.actor.id, dragData);
if (toSuper) { this.actor.addSubacteur(dragData.id || dragData.data._id);
super._onDrop(event); super._onDropActor(event, dragData);
}
/* -------------------------------------------- */
async _onDropItem(event, dragData) {
const callSuper = await this.actor.processDropItem(event, dragData, this.objetVersConteneur);
if (callSuper) {
await super._onDropItem(event, dragData)
} }
} }
/* -------------------------------------------- */
async createItem(name, type) {
await this.actor.createEmbeddedDocuments('Item', [{ name: name, type: type }], { renderSheet: true });
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async createEmptyTache() { async createEmptyTache() {
await this.actor.createOwnedItem({ name: 'Nouvelle tache', type: 'tache' }, { renderSheet: true }); await this.createItem('Nouvelle tache', 'tache');
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async creerObjet() { async creerObjet() {
let itemType = $("#creer-equipement").val(); let itemType = $(".item-type").val();
await this.actor.createOwnedItem({ name: 'Nouveau ' + itemType, type: itemType }, { renderSheet: true }); await this.createItem('Nouveau ' + itemType, itemType);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async selectObjetType() { async selectObjetType() {
let itemType = ["objet", "arme", "armure", "conteneur", "herbe", "ingredient", "livre", "potion", "munition", "monnaie"]; let typeObjets = RdDItem.getTypeObjetsEquipement();
let options = '<span class="competence-label">Selectionnez le type d\'équipement</span><select id="creer-equipement">'; let options = `<span class="competence-label">Selectionnez le type d'équipement</span><select class="item-type">`;
for (let typeName of itemType) { for (let typeName of typeObjets) {
options += '<option value="' + typeName + '">' + typeName + '</option>' options += `<option value="${typeName}">${typeName}</option>`
} }
options += '</select>'; options += '</select>';
let d = new Dialog({ let d = new Dialog({
@ -174,12 +176,34 @@ export class RdDActorSheet extends ActorSheet {
d.render(true); d.render(true);
} }
/* -------------------------------------------- */
async selectTypeOeuvre() {
let typeOeuvres = RdDItem.getTypesOeuvres();
let options = `<span class="competence-label">Selectionnez le type d'oeuvre</span><select class="item-type">`;
for (let typeName of typeOeuvres) {
options += `<option value="${typeName}">${typeName}</option>`
}
options += '</select>';
let d = new Dialog({
title: "Créer une oeuvre",
content: options,
buttons: {
one: {
icon: '<i class="fas fa-check"></i>',
label: "Créer l'oeuvre",
callback: () => this.creerObjet()
}
}
});
d.render(true);
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
HtmlUtility._showControlWhen($(".gm-only"), game.user.isGM); HtmlUtility._showControlWhen($(".gm-only"), game.user.isGM);
HtmlUtility._showControlWhen($(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue"));
html.find('#show-hide-competences').click((event) => { html.find('#show-hide-competences').click((event) => {
this.options.showCompNiveauBase = !this.options.showCompNiveauBase; this.options.showCompNiveauBase = !this.options.showCompNiveauBase;
@ -189,29 +213,48 @@ export class RdDActorSheet extends ActorSheet {
// Everything below here is only needed if the sheet is editable // Everything below here is only needed if the sheet is editable
if (!this.options.editable) return; if (!this.options.editable) return;
html.find('.item-split').click(ev => {
const li = $(ev.currentTarget).parents(".item");
const item = this.actor.items.get(li.data("item-id"));
this.splitItem(item);
});
html.find('.item-edit').click(ev => { html.find('.item-edit').click(ev => {
const li = $(ev.currentTarget).parents(".item"); const li = $(ev.currentTarget).parents(".item");
const item = this.actor.getOwnedItem(li.data("item-id")); const item = this.actor.items.get(li.data("item-id"));
item.sheet.render(true);
});
html.find('.display-label a').click((event) => {
let myID = event.currentTarget.attributes['data-item-id'].value;
const item = this.actor.getEmbeddedDocument('Item', myID);
item.sheet.render(true); item.sheet.render(true);
}); });
// Update Inventory Item
html.find('.rencontre-delete').click(ev => { html.find('.rencontre-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item"); const li = $(ev.currentTarget).parents(".item");
const rencontreKey = li.data("item-id"); const rencontreKey = li.data("item-id");
this.actor.deleteTMRRencontre(rencontreKey); this.actor.deleteTMRRencontre(rencontreKey);
}); });
// Delete Inventory Item
html.find('.item-delete').click(ev => { html.find('.item-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item"); const li = $(ev.currentTarget).parents(".item");
RdDUtility.confirmerSuppression(this, li); RdDUtility.confirmerSuppression(this, li);
}); });
html.find('.item-vendre').click(ev => {
const li = $(ev.currentTarget).parents(".item");
const itemId = li.data("item-id");
const item = this.actor.getObjet(itemId);
item?.proposerVente();
});
html.find('.item-action').click(ev => {
const li = $(ev.currentTarget).parents(".item");
const itemId = li.data("item-id");
const item = this.actor.getObjet(itemId);
this.actor.actionItem(item);
});
html.find('.subacteur-delete').click(ev => { html.find('.subacteur-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item"); const li = $(ev.currentTarget).parents(".item");
RdDUtility.confirmerSuppressionSubacteur(this, li); RdDUtility.confirmerSuppressionSubacteur(this, li);
}); });
html.find('#encaisser-direct').click(ev => { html.find('.encaisser-direct').click(ev => {
this.actor.encaisser(); this.actor.encaisser();
}); });
@ -221,12 +264,15 @@ export class RdDActorSheet extends ActorSheet {
ev.preventDefault(); ev.preventDefault();
} }
}); });
html.find('#creer-tache').click(ev => { html.find('.creer-tache').click(ev => {
this.createEmptyTache(); this.createEmptyTache();
}); });
html.find('#creer-un-objet').click(ev => { html.find('.creer-un-objet').click(ev => {
this.selectObjetType(); this.selectObjetType();
}); });
html.find('.creer-une-oeuvre').click(ev => {
this.selectTypeOeuvre();
});
html.find('#nettoyer-conteneurs').click(ev => { html.find('#nettoyer-conteneurs').click(ev => {
this.actor.nettoyerConteneurs(); this.actor.nettoyerConteneurs();
}); });
@ -280,8 +326,8 @@ export class RdDActorSheet extends ActorSheet {
}); });
// Roll Skill // Roll Skill
html.find('.competence-label a').click((event) => { html.find('a.competence-label').click((event) => {
let compName = event.currentTarget.text; let compName = event.currentTarget.name;
this.actor.rollCompetence(compName); this.actor.rollCompetence(compName);
}); });
html.find('.tache-label a').click((event) => { html.find('.tache-label a').click((event) => {
@ -332,7 +378,15 @@ export class RdDActorSheet extends ActorSheet {
actor.sheet.render(true); actor.sheet.render(true);
} }
}); });
// Boutons spéciaux MJs
html.find('.forcer-tmr-aleatoire').click((event) => {
this.actor.cacheTMRetMessage();
});
html.find('.afficher-tmr').click((event) => {
this.actor.afficheTMRetMessage();
});
// Points de reve actuel // Points de reve actuel
html.find('.ptreve-actuel a').click((event) => { html.find('.ptreve-actuel a').click((event) => {
this.actor.rollCarac('reve-actuel'); this.actor.rollCarac('reve-actuel');
@ -356,49 +410,29 @@ export class RdDActorSheet extends ActorSheet {
} }
}); });
// Display TMR, visuualisation // Display TMR, visuualisation
html.find('#visu-tmr').click((event) => { html.find('.visu-tmr').click((event) => {
this.actor.displayTMR("visu"); this.actor.displayTMR("visu");
}); });
// Display TMR, normal // Display TMR, normal
html.find('#monte-tmr').click((event) => { html.find('.monte-tmr').click((event) => {
this.actor.displayTMR("normal"); this.actor.displayTMR("normal");
}); });
// Display TMR, fast // Display TMR, fast
html.find('#monte-tmr-rapide').click((event) => { html.find('.monte-tmr-rapide').click((event) => {
this.actor.displayTMR("rapide"); this.actor.displayTMR("rapide");
}); });
html.find('#dormir-une-heure').click((event) => { html.find('.dormir-une-heure').click((event) => {
this.actor.dormir(1); this.actor.dormir(1);
}); });
html.find('#dormir-chateau-dormant').click((event) => { html.find('.dormir-chateau-dormant').click((event) => {
this.actor.dormirChateauDormant(); this.actor.dormirChateauDormant();
}); });
html.find('#enlever-tous-effets').click((event) => { html.find('.enlever-tous-effets').click((event) => {
this.actor.enleverTousLesEffets(); this.actor.enleverTousLesEffets();
}); });
// Display info about queue
html.find('.queuesouffle-label a').click((event) => {
let myID = event.currentTarget.attributes['data-item-id'].value;
const item = this.actor.getOwnedItem(myID);
item.sheet.render(true);
});
// Info sort
html.find('.sort-label a').click((event) => {
let myID = event.currentTarget.attributes['data-id'].value;
const item = this.actor.getOwnedItem(myID);
item.sheet.render(true);
});
// Info sort
html.find('.case-label a').click((event) => {
let myID = event.currentTarget.attributes['data-id'].value;
const item = this.actor.getOwnedItem(myID);
item.sheet.render(true);
});
// Display info about queue
html.find('.conteneur-name a').click((event) => { html.find('.conteneur-name a').click((event) => {
let myID = event.currentTarget.attributes['data-item-id'].value; let myID = event.currentTarget.attributes['data-item-id'].value;
RdDUtility.toggleAfficheContenu(myID); RdDUtility.toggleAfficheContenu(myID);
@ -492,7 +526,7 @@ export class RdDActorSheet extends ActorSheet {
this.render(true); this.render(true);
}); });
html.find('#ethylisme-test').click((event) => { html.find('#ethylisme-test').click((event) => {
this.actor.ethylismeTest(); this.actor.jetEthylisme();
this.render(true); this.render(true);
}); });
@ -559,8 +593,10 @@ export class RdDActorSheet extends ActorSheet {
/** @override */ /** @override */
setPosition(options = {}) { setPosition(options = {}) {
const position = super.setPosition(options); const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetTabs = this.element.find(".sheet-tabs");
const sheetBody = this.element.find(".sheet-body"); const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - 192; const bodyHeight = position.height - sheetHeader[0].clientHeight - sheetTabs[0].clientHeight;
sheetBody.css("height", bodyHeight); sheetBody.css("height", bodyHeight);
return position; return position;
} }
@ -572,4 +608,19 @@ export class RdDActorSheet extends ActorSheet {
// Update the Actor // Update the Actor
return this.object.update(formData); return this.object.update(formData);
} }
async splitItem(item) {
const dialog = await DialogSplitItem.create(item, (item, split) => this._onSplitItem(item, split));
dialog.render(true);
}
async _onSplitItem(item, split) {
if (split >= 1 && split < Misc.data(item).data.quantite) {
await item.diminuerQuantite(split);
const itemData = duplicate( Misc.data(item));
itemData.data.quantite = split;
await this.actor.createEmbeddedDocuments('Item', [itemData])
}
}
} }

View File

@ -34,12 +34,26 @@ export class RdDActorVehiculeSheet extends ActorSheet {
/* -------------------------------------------- */ /* -------------------------------------------- */
async getData() { async getData() {
let formData = super.getData(); const objectData = Misc.data(this.object);
let formData = {
formData.itemsByType = Misc.classify(formData.items); title: this.title,
id: objectData.id,
type: objectData.type,
img: objectData.img,
name: objectData.name,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
data: foundry.utils.deepClone(Misc.templateData(this.object)),
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
limited: this.object.limited,
options: this.options,
owner: this.document.isOwner,
itemsByType: Misc.classify(this.object.items.map(i => foundry.utils.deepClone(i.data))),
};
RdDUtility.filterItemsPerTypeForSheet(formData); RdDUtility.filterItemsPerTypeForSheet(formData);
RdDUtility.buildArbreDeConteneur(this, formData); this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
formData.options.isGM = game.user.isGM; formData.options.isGM = game.user.isGM;
@ -54,10 +68,10 @@ export class RdDActorVehiculeSheet extends ActorSheet {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async _onDrop(event) { async _onDropItem(event, dragData) {
let toSuper = await RdDUtility.processItemDropEvent(this, event); const callSuper = await this.actor.processDropItem(event, dragData, this.objetVersConteneur);
if ( toSuper) { if (callSuper) {
super._onDrop(event); await super._onDropItem(event, dragData)
} }
} }
@ -74,7 +88,7 @@ export class RdDActorVehiculeSheet extends ActorSheet {
// Update Inventory Item // Update Inventory Item
html.find('.item-edit').click(ev => { html.find('.item-edit').click(ev => {
const li = $(ev.currentTarget).parents(".item"); const li = $(ev.currentTarget).parents(".item");
const item = this.actor.getOwnedItem(li.data("itemId")); const item = this.actor.getEmbeddedDocument('Item', li.data("itemId"));
item.sheet.render(true); item.sheet.render(true);
}); });
// Delete Inventory Item // Delete Inventory Item
@ -94,10 +108,12 @@ export class RdDActorVehiculeSheet extends ActorSheet {
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
setPosition(options={}) { setPosition(options = {}) {
const position = super.setPosition(options); const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetTabs = this.element.find(".sheet-tabs");
const sheetBody = this.element.find(".sheet-body"); const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - 192; const bodyHeight = position.height - sheetHeader[0].clientHeight - sheetTabs[0].clientHeight;
sheetBody.css("height", bodyHeight); sheetBody.css("height", bodyHeight);
return position; return position;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,4 @@
import { Misc } from "./misc.js";
/** /**
* Class providing helper methods to get the list of users, and * Class providing helper methods to get the list of users, and
@ -7,31 +8,45 @@ export class ChatUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static onSocketMessage(sockmsg) { static onSocketMessage(sockmsg) {
switch (sockmsg.msg) { switch (sockmsg.msg) {
case "msg_delete_chat_message": return ChatUtility.onRemoveMessages(sockmsg.part, sockmsg.gmId); case "msg_delete_chat_message": return ChatUtility.onRemoveMessages(sockmsg.data);
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static onRemoveMessages(part, gmId) { static onRemoveMessages(data) {
if (game.user._id == gmId) { if (game.user.isGM || game.user.id == data.gmId) {
const toDelete = game.messages.filter(it => it.data.content.includes(part)); if (data.part){
toDelete.forEach(it => it.delete()); const toDelete = game.messages.filter(it => it.data.content.includes(data.part));
toDelete.forEach(it => it.delete());
}
if (data.messageId){
game.messages.get(data.messageId)?.delete();
}
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static removeChatMessageContaining(part) { static removeChatMessageContaining(part) {
const gmId = game.user.isGM ? game.user._id : game.users.entities.find(u => u.isGM && u.active)?.id; const removeMessageData = {
part: part,
gmId: Misc.connectedGMOrUser()
};
if (!gmId || game.user.isGM) { if (game.user.isGM) {
ChatUtility.onRemoveMessages(part, game.user._id); ChatUtility.onRemoveMessages(removeMessageData);
} }
else { else {
game.socket.emit("system.foundryvtt-reve-de-dragon", { game.socket.emit("system.foundryvtt-reve-de-dragon", { msg: "msg_delete_chat_message", data: removeMessageData });
msg: "msg_delete_chat_message", data: { }
part:part, }
gmId: gmId,
}}); static removeChatMessageId(messageId) {
const removeMessageData = { messageId: messageId, gmId: Misc.connectedGMOrUser() };
if (game.user.isGM) {
ChatUtility.onRemoveMessages(removeMessageData);
}
else {
game.socket.emit("system.foundryvtt-reve-de-dragon", { msg: "msg_delete_chat_message", data: removeMessageData });
} }
} }
@ -47,7 +62,7 @@ export class ChatUtility {
if (!game.user.isGM) { if (!game.user.isGM) {
ChatUtility.blindMessageToGM(chatOptions); ChatUtility.blindMessageToGM(chatOptions);
chatOptions.whisper = [game.user._id]; chatOptions.whisper = [game.user.id];
chatOptions.content = "Message envoyé en aveugle au Gardien"; chatOptions.content = "Message envoyé en aveugle au Gardien";
} }
else { else {
@ -65,7 +80,7 @@ export class ChatUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static prepareChatMessage(rollMode, name) { static prepareChatMessage(rollMode, name) {
return { return {
user: game.user._id, user: game.user.id,
whisper: ChatUtility.getWhisperRecipients(rollMode, name) whisper: ChatUtility.getWhisperRecipients(rollMode, name)
} }
} }
@ -75,7 +90,7 @@ export class ChatUtility {
switch (rollMode) { switch (rollMode) {
case "blindroll": return ChatUtility.getUsers(user => user.isGM); case "blindroll": return ChatUtility.getUsers(user => user.isGM);
case "gmroll": return ChatUtility.getWhisperRecipientsAndGMs(name); case "gmroll": return ChatUtility.getWhisperRecipientsAndGMs(name);
case "selfroll": return [game.user._id]; case "selfroll": return [game.user.id];
} }
return undefined; return undefined;
} }
@ -104,9 +119,9 @@ export class ChatUtility {
static handleGMChatMessage(data) { static handleGMChatMessage(data) {
console.log("blindMessageToGM", data); console.log("blindMessageToGM", data);
if (game.user.isGM) { // message privé pour GM only if (game.user.isGM) { // message privé pour GM only
data.user = game.user._id; data.user = game.user.id;
ChatMessage.create(data); ChatMessage.create(data);
} }
} }
} }

1
module/constants.js Normal file
View File

@ -0,0 +1 @@
export const SYSTEM_RDD = "foundryvtt-reve-de-dragon";

View File

@ -1,27 +0,0 @@
import { RdDDice } from "./rdd-dice.js";
export class DeDraconique extends Roll{
static async ddr(rollMode=undefined) {
let ddr = new DeDraconique().evaluate();
await RdDDice.show(ddr, rollMode);
return ddr;
}
constructor(){
super("1d8x8 - 0")
}
evaluate() {
super.evaluate();
const rerolls = Math.ceil(this.total / 8);
this.terms[this.terms.length - 1] = rerolls;
this.results[this.results.length - 1] = rerolls;
this._total -= rerolls;
return this;
}
async render(chatOptions) {
return super.render(chatOptions)
}
}

View File

@ -0,0 +1,82 @@
import { Misc } from "./misc.js";
export class DialogConsommer extends Dialog {
static async create(actor, item, template = undefined, options = {}) {
const consommerData = DialogConsommer.prepareData(actor, item, options);
const html = await renderTemplate(template ?? `systems/foundryvtt-reve-de-dragon/templates/consommer/dialog-${Misc.data(item).type}.html`, consommerData);
return new DialogConsommer(actor, item, consommerData, html, options)
}
constructor(actor, item, consommerData, html, options = {}) {
mergeObject(options, { classes: ["dialogconsommer"], width: 600, height: 500, 'z-index': 99999 }, { overwrite: false })
let conf = {
title: consommerData.title,
content: html,
default: consommerData.buttonName,
buttons: {
[consommerData.buttonName]: {
label: consommerData.buttonName, callback: it => {
this.actor.consommer(this.item, this.consommerData.choix);
}
}
}
};
super(conf, options);
this.actor = actor;
this.item = item;
this.consommerData = consommerData;
}
/* -------------------------------------------- */
static prepareData(actor, item, options) {
const itemData = duplicate(Misc.data(item));
let consommerData = {
item: itemData,
cuisine: Misc.data(actor.getCompetence('cuisine')),
choix: {
doses: options.doses ?? 1,
seForcer: options.seForcer ?? false,
}
}
switch (itemData.type) {
case 'nourritureboisson':
consommerData.title = itemData.data.boisson ? `${itemData.name}: boire une dose` : `${itemData.name}: manger une portion`;
consommerData.buttonName = itemData.data.boisson ? "Boire" : "Manger";
break;
case 'potion':
consommerData.title = `${itemData.name}: boire la potion`;
consommerData.buttonName = "Boire";
break;
}
DialogConsommer.calculDoses(consommerData, consommerData.choix.doses)
return consommerData;
}
static calculDoses(consommerData) {
const doses = consommerData.choix.doses;
consommerData.totalSust = Misc.keepDecimals(doses * (consommerData.item.data.sust ?? 0), 2);
consommerData.totalDesaltere = consommerData.item.data.boisson
? Misc.keepDecimals(doses * (consommerData.item.data.desaltere ?? 0), 2)
: 0;
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
html.find(".se-forcer").change(event => {
this.consommerData.choix.seForcer = event.currentTarget.checked;
});
html.find(".consommer-doses").change(event => {
this.consommerData.choix.doses = Number(event.currentTarget.value);
DialogConsommer.calculDoses(this.consommerData);
$(".total-sust").text(this.consommerData.totalSust)
$(".total-desaltere").text(this.consommerData.totalDesaltere)
});
}
}

View File

@ -0,0 +1,116 @@
import { ChatUtility } from "./chat-utility.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
import { Misc } from "./misc.js";
import { RdDRollTables } from "./rdd-rolltables.js";
import { TMRType, TMRUtility } from "./tmr-utility.js";
export class DialogCreateSigneDraconique extends Dialog {
static async createSigneForActors() {
const signe = await RdDItemSigneDraconique.randomSigneDraconique();
let dialogData = {
signe: signe,
tmrs: TMRUtility.listSelectedTMR(signe.data.typesTMR ?? []),
actors: game.actors.filter(actor => actor.isHautRevant()).map(actor => {
let actorData = duplicate(Misc.data(actor));
actorData.selected = actor.hasPlayerOwner;
return actorData;
})
};
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-create-signedraconique.html", dialogData);
new DialogCreateSigneDraconique(dialogData, html)
.render(true);
}
constructor(dialogData, html, callback) {
let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 500, height: 650, 'z-index': 99999 };
let conf = {
title: "Créer un signe",
content: html,
default: "Ajouter aux haut-rêvants",
buttons: {
"Ajouter aux haut-rêvants": { label: "Ajouter aux haut-rêvants", callback: it => { this._onCreerSigneActeurs(); } }
}
};
super(conf, options);
this.dialogData = dialogData;
}
async _onCreerSigneActeurs() {
this.validerSigne();
this.dialogData.actors.filter(it => it.selected).map(it => game.actors.get(it._id))
.forEach(actor => this._createSigneForActor(actor, this.dialogData.signe));
}
async _createSigneForActor(actor, signe) {
actor.createEmbeddedDocuments("Item", [signe]);
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(Misc.data(actor).name),
content: await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html", {
signe: signe,
alias: Misc.data(actor).name
})
});
}
validerSigne() {
this.dialogData.signe.name = $("[name='signe.name']").val();
this.dialogData.signe.data.valeur.norm = $("[name='signe.data.valeur.norm']").val();
this.dialogData.signe.data.valeur.sign = $("[name='signe.data.valeur.sign']").val();
this.dialogData.signe.data.valeur.part = $("[name='signe.data.valeur.part']").val();
this.dialogData.signe.data.difficulte = $("[name='signe.data.difficulte']").val();
this.dialogData.signe.data.ephemere = $("[name='signe.data.ephemere']").prop("checked");
this.dialogData.signe.data.duree = $("[name='signe.data.duree']").val();
this.dialogData.signe.data.typesTMR = $(".select-tmr").val();
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
this.setEphemere(this.dialogData.signe.data.ephemere);
html.find(".signe-aleatoire").click(event => this.setSigneAleatoire());
html.find("[name='signe.data.ephemere']").change((event) => this.setEphemere(event.currentTarget.checked));
html.find(".select-actor").change((event) => this.onSelectActor(event));
html.find(".signe-xp-sort").change((event) => this.onValeurXpSort(event));
}
async setSigneAleatoire() {
const newSigne = await RdDItemSigneDraconique.randomSigneDraconique();
$("[name='signe.name']").val(newSigne.name);
$("[name='signe.data.valeur.norm']").val(newSigne.data.valeur.norm);
$("[name='signe.data.valeur.sign']").val(newSigne.data.valeur.sign);
$("[name='signe.data.valeur.part']").val(newSigne.data.valeur.part);
$("[name='signe.data.difficulte']").val(newSigne.data.difficulte);
$("[name='signe.data.duree']").val(newSigne.data.duree);
$("[name='signe.data.ephemere']").prop("checked", newSigne.data.ephemere);
$(".select-tmr").val(newSigne.data.typesTMR);
this.setEphemere(newSigne.data.ephemere);
}
async setEphemere(ephemere) {
this.dialogData.signe.data.ephemere = ephemere;
HtmlUtility._showControlWhen($(".signe-data-duree"), ephemere);
}
async onSelectActor(event) {
event.preventDefault();
const options = event.currentTarget.options;
for (var i = 0; i < options.length; i++) { // looping over the options
const actorId = options[i].attributes["data-actor-id"].value;
const actor = this.dialogData.actors.find(it => it._id == actorId);
if (actor) {
actor.selected = options[i].selected;
}
};
}
onValeurXpSort(event) {
const codeReussite = event.currentTarget.attributes['data-typereussite']?.value ?? 0;
const xp = Number(event.currentTarget.value);
const oldValeur = this.dialogData.signe.data.valeur;
this.dialogData.signe.data.valeur = RdDItemSigneDraconique.calculValeursXpSort(codeReussite, xp, oldValeur);
}
}

View File

@ -0,0 +1,64 @@
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js";
export class DialogFabriquerPotion extends Dialog {
/* -------------------------------------------- */
static async create(actor, item, dialogConfig) {
let potionData = DialogFabriquerPotion.prepareData(actor, item);
let conf = {
title: `Fabriquer une potion de ${potionData.data.categorie}`,
content: await renderTemplate(dialogConfig.html, potionData),
default: potionData.buttonName,
};
let options = { classes: ["dialogfabriquerpotion"], width: 600, height: 160, 'z-index': 99999 };
mergeObject(options, dialogConfig.options ?? {}, { overwrite: true })
const dialog = new DialogFabriquerPotion(actor, potionData, conf, options);
dialog.render(true);
return dialog;
}
/* -------------------------------------------- */
static prepareData(actor, item) {
let potionData = duplicate(Misc.data(item));
potionData.nbBrinsSelect = RdDUtility.buildListOptions( 1, potionData.data.quantite);
potionData.nbBrins = potionData.data.quantite;
potionData.buttonName = "Fabriquer";
return potionData;
}
/* -------------------------------------------- */
constructor(actor, potionData, conf, options) {
conf.buttons = {
[potionData.buttonName]: {
label: potionData.buttonName, callback: it => {
this.fabriquer();
}
}
};
super(conf, options);
this.actor = actor;
this.potionData = potionData;
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
html.find("#nbBrins").change(event => {
this.potionData.nbBrins = Misc.toInt(event.currentTarget.value);
});
}
/* -------------------------------------------- */
async fabriquer() {
this.actor.fabriquerPotion( this.potionData );
this.close();
}
}

View File

@ -0,0 +1,87 @@
import { RdDActor } from "./actor.js";
import { HtmlUtility } from "./html-utility.js";
import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js";
export class DialogItemAchat extends Dialog {
static async onButtonAcheter(event) {
let jsondata = event.currentTarget.attributes['data-jsondata']?.value;
if (!jsondata) {
ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes")
return;
}
const vendeurId = event.currentTarget.attributes['data-vendeurId']?.value;
const vendeur = vendeurId ? game.actors.get(vendeurId) : undefined;
const acheteur = RdDUtility.getSelectedActor();
if (!acheteur && !vendeur) {
ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement");
return;
}
const chatMessageIdVente = RdDUtility.findChatMessageId(event.currentTarget);
const itemData = JSON.parse(jsondata);
const prixLot = event.currentTarget.attributes['data-prixLot']?.value ?? 0;
let venteData = {
item: itemData,
vendeurId: vendeurId,
vendeur: Misc.data(vendeur),
acheteur: Misc.data(acheteur),
tailleLot: event.currentTarget.attributes['data-tailleLot']?.value ?? 1,
quantiteNbLots: event.currentTarget.attributes['data-quantiteNbLots']?.value,
nombreLots: 1,
prixLot: prixLot,
prixTotal: prixLot,
isVente: prixLot > 0
};
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData);
const dialog = new DialogItemAchat(html, vendeur, acheteur, venteData, chatMessageIdVente);
dialog.render(true);
}
constructor(html, vendeur, acheteur, venteData, chatMessageIdVente) {
let options = { classes: ["dialogachat"], width: 400, height: 300, 'z-index': 99999 };
const actionAchat = venteData.prixLot > 0 ? "Acheter" : "Prendre";
let conf = {
title: actionAchat,
content: html,
default: actionAchat,
buttons: {
[actionAchat]: { label: actionAchat, callback: it => { this.onAchat(); } },
"decliner": { label: "Décliner", callback: it => { } }
}
};
super(conf, options);
this.vendeur = vendeur;
this.acheteur = acheteur;
this.chatMessageIdVente = chatMessageIdVente;
this.venteData = venteData;
}
async onAchat() {
(this.vendeur ?? this.acheteur).achatVente(
this.vendeur?.id,
this.acheteur?.id,
this.venteData,
this.chatMessageIdVente
);
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
html.find(".nombreLots").change(event => this.setnombreLots(Number(event.currentTarget.value)));
}
setnombreLots(nombreLots) {
this.venteData.nombreLots = nombreLots;
this.venteData.prixTotal = (nombreLots * this.venteData.prixLot).toFixed(2);
$(".prixTotal").text(this.venteData.prixTotal);
}
}

View File

@ -0,0 +1,90 @@
import { HtmlUtility } from "./html-utility.js";
import { Misc } from "./misc.js";
export class DialogItemVente extends Dialog {
static async create(item, callback) {
const itemData = Misc.data(item);
const venteData = {
item: itemData,
alias: item.actor?.name ?? game.user.name,
vendeurId: item.actor?.id,
prixOrigine: itemData.data.cout,
prixUnitaire: itemData.data.cout,
prixLot: itemData.data.cout,
tailleLot: 1,
quantiteNbLots: itemData.data.quantite,
quantiteMaxLots: itemData.data.quantite,
quantiteMax: itemData.data.quantite,
quantiteIllimite: !item.isOwned,
isOwned: item.isOwned,
};
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.html`, venteData);
return new DialogItemVente(venteData, html, callback);
}
constructor(venteData, html, callback) {
let options = { classes: ["dialogvente"], width: 400, height: 300, 'z-index': 99999 };
let conf = {
title: "Proposer",
content: html,
default: "proposer",
buttons: { "proposer": { label: "Proposer", callback: it => { this.onProposer(); } } }
};
super(conf, options);
this.callback = callback;
this.venteData = venteData;
}
async onProposer() {
this.callback(this.venteData);
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
HtmlUtility._showControlWhen($(".quantiteNbLots"), !this.venteData.quantiteIllimite)
html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value)));
html.find(".quantiteNbLots").change(event => this.setNbLots(Number(event.currentTarget.value)));
html.find(".quantiteIllimite").change(event => this.setQuantiteIllimite(event.currentTarget.checked));
html.find(".prixLot").change(event => this.setPrixLot(Number(event.currentTarget.value)));
}
setPrixLot(prixLot) {
this.venteData.prixLot = prixLot;
}
setTailleLot(tailleLot) {
// recalculer le prix du lot
if (tailleLot != this.venteData.tailleLot) {
this.venteData.prixLot = (tailleLot * this.venteData.prixOrigine).toFixed(2);
$(".prixLot").val(this.venteData.prixLot);
}
this.venteData.tailleLot = tailleLot;
if (this.venteData.isOwned) {
// recalculer le nombre de lots max
this.venteData.quantiteMaxLots = Math.floor(this.venteData.quantiteMax / tailleLot);
this.venteData.quantiteNbLots = Math.min(this.venteData.quantiteMaxLots, this.venteData.quantiteNbLots);
$(".quantiteNbLots").val(this.venteData.quantiteNbLots);
$(".quantiteNbLots").attr("max", this.venteData.quantiteMaxLots)
}
}
setNbLots(nbLots) {
if (this.venteData.isOwned) {
nbLots = Math.max(0, Math.min(nbLots, this.venteData.quantiteMaxLots));
}
this.venteData.quantiteNbLots = nbLots;
$(".quantiteNbLots").val(this.venteData.quantiteNbLots);
}
setQuantiteIllimite(checked) {
this.venteData.quantiteIllimite = checked;
$(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles");
HtmlUtility._showControlWhen($(".quantiteNbLots"), !this.venteData.quantiteIllimite)
}
}

View File

@ -0,0 +1,51 @@
import { Misc } from "./misc.js";
export class DialogSplitItem extends Dialog {
static async create(item, callback) {
const itemData = Misc.data(item);
const splitData = {
item: itemData,
choix: { quantite: 1, max: itemData.data.quantite - 1 }
};
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-split.html`, splitData);
return new DialogSplitItem(item, splitData, html, callback)
}
constructor(item, splitData, html, callback) {
let options = { classes: ["dialogsplit"], width: 300, height: 160, 'z-index': 99999 };
let conf = {
title: "Séparer en deux",
content: html,
default: "separer",
buttons: {
"separer": {
label: "Séparer", callback: it => {
this.onSplit();
}
}
}
};
super(conf, options);
this.callback = callback;
this.item = item;
this.splitData = splitData;
}
async onSplit(){
this.callback(this.item, this.splitData.choix.quantite);
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
html.find(".choix-quantite").change(event => {
this.splitData.choix.quantite = Number(event.currentTarget.value);
});
}
}

View File

@ -3,7 +3,7 @@ import { RdDUtility } from "./rdd-utility.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
// Activate chat listeners defined // Activate chat listeners defined
Hooks.on('renderChatLog', (log, html, data) => { // Hooks.on('renderChatLog', (log, html, data) => {
RdDUtility.chatListeners(html); // RdDUtility.chatListeners(html);
}); // });

View File

@ -1,8 +1,11 @@
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
const competenceTroncs = [["Esquive", "Dague", "Corps à corps"], const competenceTroncs = [["Esquive", "Dague", "Corps à corps"],
["Epée à 1 main", "Epée à 2 mains", "Hache à 1 main", "Hache à 2 mains", "Lance", "Masse à 1 main", "Masse à 2 mains"]]; ["Epée à 1 main", "Epée à 2 mains", "Hache à 1 main", "Hache à 2 mains", "Lance", "Masse à 1 main", "Masse à 2 mains"]];
const competence_xp_par_niveau = [5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20, 30, 30, 40, 40, 60, 60, 100, 100, 100, 100, 100, 100, 100, 100, 100]; const xp_par_niveau = [5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20, 30, 30, 40, 40, 60, 60, 100, 100, 100, 100, 100, 100, 100, 100, 100];
const competence_niveau_max = competence_xp_par_niveau.length - 10; const niveau_max = xp_par_niveau.length - 10;
/* -------------------------------------------- */ /* -------------------------------------------- */
const limitesArchetypes = [ const limitesArchetypes = [
{ "niveau": 0, "nombreMax": 100, "nombre": 0 }, { "niveau": 0, "nombreMax": 100, "nombre": 0 },
@ -21,14 +24,14 @@ const limitesArchetypes = [
/* -------------------------------------------- */ /* -------------------------------------------- */
const categorieCompetences = { const categorieCompetences = {
"generale": { level: "-4", label: "Générales" }, "generale": { base: -4, label: "Générales" },
"particuliere": { level: "-8", label: "Particulières" }, "particuliere": { base: -8, label: "Particulières" },
"specialisee": { level: "-11", label: "Spécialisées" }, "specialisee": { base: -11, label: "Spécialisées" },
"connaissance": { level: "-11", label: "Connaissances" }, "connaissance": { base: -11, label: "Connaissances" },
"draconic": { level: "-11", label: "Draconics" }, "draconic": { base: -11, label: "Draconics" },
"melee": { level: "-6", label: "Mêlée" }, "melee": { base: -6, label: "Mêlée" },
"tir": { level: "-8", label: "Tir" }, "tir": { base: -8, label: "Tir" },
"lancer": { level: "-8", label: "Lancer" } "lancer": { base: -8, label: "Lancer" }
} }
const compendiumCompetences = { const compendiumCompetences = {
@ -41,9 +44,9 @@ const compendiumCompetences = {
function _buildCumulXP() { function _buildCumulXP() {
let cumulXP = { "-11": 0 }; let cumulXP = { "-11": 0 };
let cumul = 0; let cumul = 0;
for (let i = 0; i <= competence_xp_par_niveau.length; i++) { for (let i = 0; i <= xp_par_niveau.length; i++) {
let level = i - 10; let level = i - 10;
cumul += competence_xp_par_niveau[i]; cumul += xp_par_niveau[i];
cumulXP[level] = cumul; cumulXP[level] = cumul;
} }
return cumulXP; return cumulXP;
@ -53,29 +56,48 @@ const competence_xp_cumul = _buildCumulXP();
export class RdDItemCompetence extends Item { export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static actorCompendium(actorType) { static actorCompendium(actorType) {
return compendiumCompetences[actorType]; return compendiumCompetences[actorType];
} }
/* -------------------------------------------- */
static getCategorieCompetences() { static getCategorieCompetences() {
return categorieCompetences; return categorieCompetences;
} }
/* -------------------------------------------- */
static getNiveauBase(category) { static getNiveauBase(category) {
return categorieCompetences[category].level; return categorieCompetences[category].base;
} }
/* -------------------------------------------- */
static getLabelCategorie(category) { static getLabelCategorie(category) {
return categorieCompetences[category].label; return categorieCompetences[category].label;
} }
/* -------------------------------------------- */
static getCategorie(competence) {
return Misc.data(competence)?.data.categorie;
}
static isDraconic(competence) {
return Misc.data(competence).data.categorie == 'draconic';
}
/* -------------------------------------------- */
static getVoieDraconic(competences, voie) {
voie = Grammar.toLowerCaseNoAccent(voie);
return competences.find(it => RdDItemCompetence.isDraconic(it) && Grammar.toLowerCaseNoAccent(Misc.data(it).name).includes(voie));
}
/* -------------------------------------------- */
static getEsquive(competences) { static getEsquive(competences) {
return { name: 'Esquive', niveau: RdDItemCompetence.findCompetence(competences, 'Esquive')?.data.niveau ?? -6 }; return { name: 'Esquive', niveau: RdDItemCompetence.findCompetence(competences, 'Esquive')?.data.niveau ?? -6 };
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static isCompetenceArme(competence) { static isCompetenceArme(competence) {
switch (competence.data.categorie) { switch (Misc.templateData(competence).categorie) {
case 'melee': case 'melee':
return competence.name != 'Esquive'; return Misc.data(competence).name != 'Esquive';
case 'tir': case 'tir':
case 'lancer': case 'lancer':
return true; return true;
@ -85,15 +107,15 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static isArmeUneMain(competence) { static isArmeUneMain(competence) {
return competence?.name.toLowerCase().includes("1 main"); return Misc.data(competence)?.name.toLowerCase().includes("1 main");
} }
static isArme2Main(competence) { static isArme2Main(competence) {
return competence?.name.toLowerCase().includes("2 main"); return Misc.data(competence)?.name.toLowerCase().includes("2 main");
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static isMalusEncombrementTotal(competence) { static isMalusEncombrementTotal(competence) {
return competence?.name.toLowerCase().match(/(natation|acrobatie)/); return Misc.data(competence)?.name.toLowerCase().match(/(natation|acrobatie)/);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -110,17 +132,18 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static computeTotalXP(competences) { static computeTotalXP(competences) {
const total = competences.map(c => RdDItemCompetence.computeXP(c)) const total = competences.map(c => RdDItemCompetence.computeXP(c))
.reduce((a, b) => a + b, 0); .reduce(Misc.sum(), 0);
const economieTronc = RdDItemCompetence.computeEconomieXPTronc(competences); const economieTronc = RdDItemCompetence.computeEconomieXPTronc(competences);
return total - economieTronc; return total - economieTronc;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static computeXP(competence) { static computeXP(competence) {
const factor = competence.name.includes('Thanatos') ? 2 : 1; // Thanatos compte double ! const itemData = Misc.data(competence);
const xpNiveau = RdDItemCompetence.computeDeltaXP(competence.data.base, competence.data.niveau ?? competence.data.base); const factor = itemData.name.includes('Thanatos') ? 2 : 1; // Thanatos compte double !
const xp = competence.data.xp ?? 0; const xpNiveau = RdDItemCompetence.computeDeltaXP(itemData.data.base, itemData.data.niveau ?? itemData.data.base);
const xpSort = competence.data.xp_sort ?? 0; const xp = itemData.data.xp ?? 0;
const xpSort = itemData.data.xp_sort ?? 0;
return factor * (xpNiveau + xp) + xpSort; return factor * (xpNiveau + xp) + xpSort;
} }
@ -128,12 +151,12 @@ export class RdDItemCompetence extends Item {
static computeEconomieXPTronc(competences) { static computeEconomieXPTronc(competences) {
return competenceTroncs.map( return competenceTroncs.map(
list => list.map(name => RdDItemCompetence.findCompetence(competences, name)) list => list.map(name => RdDItemCompetence.findCompetence(competences, name))
// calcul du coût xp jusqu'au niveau 0 maximum // calcul du coût xp jusqu'au niveau 0 maximum
.map(it => RdDItemCompetence.computeDeltaXP(it?.data.base ?? -11, Math.min(it?.data.niveau ?? -11, 0))) .map(it => RdDItemCompetence.computeDeltaXP(it?.data.base ?? -11, Math.min(it?.data.niveau ?? -11, 0)))
.sort((a, b) => b - a) // tri descendant .sort(Misc.ascending())
.splice(0, 1) // ignorer le coût xp le plus élevé .splice(0, list.length-1) // prendre toutes les valeurs sauf l'une des plus élevées
.reduce((a, b) => a + b, 0) .reduce(Misc.sum(), 0)
).reduce((a, b) => a + b, 0); ).reduce(Misc.sum(), 0);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -146,10 +169,11 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static computeCompetenceXPCost(competence) { static computeCompetenceXPCost(competence) {
let xp = RdDItemCompetence.getDeltaXp(competence.data.base, competence.data.niveau ?? competence.data.base); const compData = Misc.data(competence);
xp += competence.data.xp ?? 0; let xp = RdDItemCompetence.getDeltaXp(compData.data.base, compData.data.niveau ?? compData.data.base);
if (competence.name.includes('Thanatos')) xp *= 2; /// Thanatos compte double ! xp += compData.data.xp ?? 0;
xp += competence.data.xp_sort ?? 0; if (compData.name.includes('Thanatos')) xp *= 2; /// Thanatos compte double !
xp += compData.data.xp_sort ?? 0;
return xp; return xp;
} }
@ -158,20 +182,22 @@ export class RdDItemCompetence extends Item {
let economie = 0; let economie = 0;
for (let troncList of competenceTroncs) { for (let troncList of competenceTroncs) {
let list = troncList.map(name => RdDItemCompetence.findCompetence(competences, name)) let list = troncList.map(name => RdDItemCompetence.findCompetence(competences, name))
.sort((c1, c2) => c2.data.niveau - c1.data.niveau); // tri du plus haut au plus bas .sort(Misc.descending(c => Misc.templateData(c).niveau)); // tri du plus haut au plus bas
list.splice(0, 1); // ignorer la plus élevée list.splice(0, 1); // ignorer la plus élevée
list.forEach(c => { list.map(c => Misc.templateData(c)).forEach(tplData => {
economie += RdDItemCompetence.getDeltaXp(c.data.base, Math.min(c.data.niveau, 0)); economie += RdDItemCompetence.getDeltaXp(tplData.base, Math.min(tplData.niveau, 0));
}); });
} }
return economie; return economie;
} }
/* -------------------------------------------- */
static levelUp(itemData) { static levelUp(itemData) {
itemData.data.xpNext = RdDItemCompetence.getCompetenceNextXp(itemData.data.niveau); itemData.data.xpNext = RdDItemCompetence.getCompetenceNextXp(itemData.data.niveau);
itemData.data.isLevelUp = itemData.data.xp >= itemData.data.xpNext; itemData.data.isLevelUp = itemData.data.xp >= itemData.data.xpNext;
} }
/* -------------------------------------------- */
static isVisible(itemData) { static isVisible(itemData) {
return Number(itemData.data.niveau) != RdDItemCompetence.getNiveauBase(itemData.data.categorie); return Number(itemData.data.niveau) != RdDItemCompetence.getNiveauBase(itemData.data.categorie);
} }
@ -183,8 +209,20 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static findCompetence(list, name) { static findCompetence(list, name) {
name = name.toLowerCase(); name = Grammar.toLowerCaseNoAccent(name);
return list.find(it => it.name.toLowerCase() == name && (it.type == "competence" || it.type == "competencecreature")) const competences = list.filter(it => Grammar.toLowerCaseNoAccent(it.name).includes(name) && (it.type == "competence" || it.type == "competencecreature"));
if (competences.length == 0) {
return undefined;
}
let competence = competences.find(it => Grammar.toLowerCaseNoAccent(it.name) == name);
if (!competence) {
competence = competences[0];
if (competences.length > 1) {
const names = competences.map(it => it.name).reduce((a, b) => `${a}<br>${b}`);
ui.notifications.info(`Plusieurs compétences possibles:<br>${names}<br>La première sera choisie: ${competence.name}`);
}
}
return competence;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -195,7 +233,7 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static getCompetenceXp(niveau) { static getCompetenceXp(niveau) {
RdDItemCompetence._valideNiveau(niveau); RdDItemCompetence._valideNiveau(niveau);
return niveau < -10 ? 0 : competence_xp_par_niveau[niveau + 10]; return niveau < -10 ? 0 : xp_par_niveau[niveau + 10];
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -207,19 +245,19 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static _valideNiveau(niveau) { static _valideNiveau(niveau) {
if (niveau < -11 || niveau > competence_niveau_max) { if (niveau < -11 || niveau > niveau_max) {
console.warn(`Niveau ${niveau} en dehors des niveaux de compétences: [-11, ${competence_niveau_max} ]`); console.warn(`Niveau ${niveau} en dehors des niveaux de compétences: [-11, ${niveau_max} ]`);
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static computeResumeArchetype(competences) { static computeResumeArchetype(competences) {
const archetype = RdDItemCompetence.getLimitesArchetypes(); const archetype = RdDItemCompetence.getLimitesArchetypes();
competences.forEach(it => { competences.map(it => Math.max(0, Misc.templateData(it).niveau_archetype))
let niveau = Math.max(0, it.data.niveau_archetype); .forEach(niveau => {
archetype[niveau] = archetype[niveau] ?? { "niveau": niveau, "nombreMax": 0, "nombre": 0 }; archetype[niveau] = archetype[niveau] ?? { "niveau": niveau, "nombreMax": 0, "nombre": 0 };
archetype[niveau].nombre = (archetype[niveau]?.nombre ?? 0) + 1; archetype[niveau].nombre = (archetype[niveau]?.nombre ?? 0) + 1;
}); });
return archetype; return archetype;
} }

View File

@ -5,8 +5,8 @@ export class RdDItemCompetenceCreature extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static setRollDataCreature(rollData) { static setRollDataCreature(rollData) {
rollData.competence = Misc.data(rollData.competence);
rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.data.carac_value } }; rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.data.carac_value } };
rollData.competence = duplicate(rollData.competence);
rollData.competence.data.defaut_carac = "carac_creature"; rollData.competence.data.defaut_carac = "carac_creature";
rollData.competence.data.categorie = "creature"; rollData.competence.data.categorie = "creature";
rollData.selectedCarac = rollData.carac.carac_creature; rollData.selectedCarac = rollData.carac.carac_creature;
@ -26,6 +26,7 @@ export class RdDItemCompetenceCreature extends Item {
competence: itemData.name, competence: itemData.name,
resistance: 100, resistance: 100,
equipe: true, equipe: true,
dommagesReels: arme.data.dommages,
penetration: 0, penetration: 0,
force: 0, force: 0,
rapide: true rapide: true

View File

@ -1,22 +1,23 @@
import { Misc } from "./misc.js";
const monnaiesData = [ const monnaiesData = [
{ {
_id: randomID(16), name: "Etain (1 denier)", type: 'monnaie', name: "Etain (1 denier)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp", img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp",
data: { quantite: 0, valeur_deniers: 1, encombrement: 0.001, description: "" } data: { quantite: 0, valeur_deniers: 1, encombrement: 0.001, description: "" }
}, },
{ {
_id: randomID(16), name: "Bronze (10 deniers)", type: 'monnaie', name: "Bronze (10 deniers)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_bronze_epees.webp", img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_bronze_epees.webp",
data: { quantite: 0, valeur_deniers: 10, encombrement: 0.002, description: "" } data: { quantite: 0, valeur_deniers: 10, encombrement: 0.002, description: "" }
}, },
{ {
_id: randomID(16), name: "Argent (1 sol)", type: 'monnaie', name: "Argent (1 sol)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_argent_sol.webp", img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_argent_sol.webp",
data: { quantite: 0, valeur_deniers: 100, encombrement: 0.003, description: "" } data: { quantite: 0, valeur_deniers: 100, encombrement: 0.003, description: "" }
}, },
{ {
_id: randomID(16), name: "Or (10 sols)", type: 'monnaie', name: "Or (10 sols)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_or_sol.webp", img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_or_sol.webp",
data: { quantite: 0, valeur_deniers: 1000, encombrement: 0.004, description: "" } data: { quantite: 0, valeur_deniers: 1000, encombrement: 0.004, description: "" }
} }
@ -29,12 +30,21 @@ export class Monnaie {
} }
static filtrerMonnaies(items) { static filtrerMonnaies(items) {
return items.filter(it => it.type == 'monnaie'); return items.filter(it => Misc.data(it).type == 'monnaie');
} }
static monnaiesManquantes(items) { static monnaiesManquantes(items) {
const valeurs = Monnaie.filtrerMonnaies(items) const valeurs = Monnaie.filtrerMonnaies(items)
.map(it => it.data.valeur_deniers) .map(it => Misc.templateData(it).valeur_deniers)
return duplicate(monnaiesData.filter(monnaie => !valeurs.find(v => v != monnaie.data.valeur_deniers))); const manquantes = monnaiesData.filter(monnaie => !valeurs.find(v => v != Misc.templateData(monnaie).valeur_deniers));
return manquantes;
}
static deValeur(monnaie, v) {
return v != monnaie.data.valeur_deniers;
}
static arrondiDeniers(sols) {
return sols.toFixed(2);
} }
} }

View File

@ -1,315 +0,0 @@
import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js";
/* -------------------------------------------- */
export class RdDItem extends Item {
/* -------------------------------------------- */
async postItem() {
console.log(this);
const properties = this[`_${this.data.type}ChatData`]();
const itemData = Misc.data(this);
let chatData = duplicate(itemData);
chatData["properties"] = properties
//Check if the posted item should have availability/pay buttons
chatData.hasPrice = "cout" in chatData.data;
chatData.data.cout_deniers = 0;
let dialogResult = [-1, -1]; // dialogResult[0] = quantité, dialogResult[1] = prix
if (chatData.hasPrice )
{
let sols = chatData.data.cout;
chatData.data.cout_deniers = Math.floor(sols * 100);
dialogResult = await new Promise( (resolve, reject) => {new Dialog({
content :
`<p>Modifier la quantité?</p>
<div class="form-group">
<label> Quantité</label>
<input name="quantity" type="text" value="1"/>
</div>
<p>Modifier la prix?</p>
<div class="form-group">
<label> Prix en Sols</label>
<input name="price" type="text" value="${chatData.data.cout}"/>
</div>
`,
title : "Quantité & Prix",
buttons : {
post : {
label : "Soumettre",
callback: (dlg) => {
resolve( [ dlg.find('[name="quantity"]').val(), dlg.find('[name="price"]').val() ] )
}
},
}
}).render(true)
})
}
if (dialogResult[0] > 0)
{
if (this.isOwned)
{
if (itemData.data.quantite == 0)
dialogResult[0] = -1
else if (itemData.data.quantite < dialogResult[0])
{
dialogResult[0] = itemData.data.quantite;
ui.notifications.notify(`Impossible de poster plus que ce que vous avez. La quantité à été réduite à ${dialogResult[0]}.`)
this.update({"data.quantite" : 0})
}
else {
ui.notifications.notify(`Quantité réduite par ${dialogResult[0]}.`)
this.update({"data.quantite" : itemData.data.quantite - dialogResult[0]})
}
}
}
if ( chatData.hasPrice ) {
if (dialogResult[0] > 0)
chatData.postQuantity = Number(dialogResult[0]);
if (dialogResult[1] > 0) {
chatData.postPrice = dialogResult[1];
chatData.data.cout_deniers = Math.floor(dialogResult[1] * 100); // Mise à jour cout en deniers
}
chatData.finalPrice = Number(chatData.postPrice) * Number(chatData.postQuantity);
chatData.data.cout_deniers_total = chatData.data.cout_deniers * Number(chatData.postQuantity);
chatData.data.quantite = chatData.postQuantity;
console.log("POST : ", chatData.finalPrice, chatData.data.cout_deniers_total, chatData.postQuantity);
}
// Don't post any image for the item (which would leave a large gap) if the default image is used
if (chatData.img.includes("/blank.png"))
chatData.img = null;
// JSON object for easy creation
chatData.jsondata = JSON.stringify(
{
compendium : "postedItem",
payload: itemData,
});
renderTemplate('systems/foundryvtt-reve-de-dragon/templates/post-item.html', chatData).then(html => {
let chatOptions = RdDUtility.chatDataSetup(html);
ChatMessage.create(chatOptions)
});
}
/* -------------------------------------------- */
_objetChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Encombrement</b>: ${rddData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_armeChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Compétence</b>: ${rddData.competence}`,
`<b>Dommages</b>: ${rddData.dommages}`,
`<b>Force minimum</b>: ${rddData.force}`,
`<b>Resistance</b>: ${rddData.resistance}`,
`<b>Encombrement</b>: ${rddData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_conteneurChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Capacité</b>: ${rddData.capacite} Enc.`,
`<b>Encombrement</b>: ${rddData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_munitionChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Encombrement</b>: ${rddData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_armureChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Protection</b>: ${rddData.protection}`,
`<b>Détérioration</b>: ${rddData.deterioration}`,
`<b>Malus armure</b>: ${rddData.malus}`,
`<b>Encombrement</b>: ${rddData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_competenceChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Catégorie</b>: ${rddData.categorie}`,
`<b>Niveau</b>: ${rddData.niveau}`,
`<b>Caractéristique par défaut</b>: ${rddData.carac_defaut}`,
`<b>XP</b>: ${rddData.xp}`
]
return properties;
}
/* -------------------------------------------- */
_competencecreatureChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Catégorie</b>: ${rddData.categorie}`,
`<b>Niveau</b>: ${rddData.niveau}`,
`<b>Caractéristique</b>: ${rddData.carac_value}`,
`<b>XP</b>: ${rddData.xp}`
]
return properties;
}
/* -------------------------------------------- */
_sortChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Draconic</b>: ${rddData.draconic}`,
`<b>Difficulté</b>: ${rddData.difficulte}`,
`<b>Case TMR</b>: ${rddData.caseTMR}`,
`<b>Points de Rêve</b>: ${rddData.ptreve}`
]
return properties;
}
/* -------------------------------------------- */
_herbeChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Milieu</b>: ${rddData.milieu}`,
`<b>Rareté</b>: ${rddData.rarete}`,
`<b>Catégorie</b>: ${rddData.categorie}`,
]
return properties;
}
/* -------------------------------------------- */
_ingredientChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Milieu</b>: ${rddData.milieu}`,
`<b>Rareté</b>: ${rddData.rarete}`,
`<b>Catégorie</b>: ${rddData.categorie}`,
]
return properties;
}
/* -------------------------------------------- */
_tacheChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Caractéristique</b>: ${rddData.carac}`,
`<b>Compétence</b>: ${rddData.competence}`,
`<b>Périodicité</b>: ${rddData.periodicite}`,
`<b>Fatigue</b>: ${rddData.fatigue}`,
`<b>Difficulté</b>: ${rddData.difficulte}`,
`<b>Points de Tâche</b>: ${rddData.points_de_tache}`,
`<b>Points de Tâche atteints</b>: ${rddData.points_de_tache_courant}`
]
return properties;
}
/* -------------------------------------------- */
_livreChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Compétence</b>: ${rddData.competence}`,
`<b>Auteur</b>: ${rddData.auteur}`,
`<b>Difficulté</b>: ${rddData.difficulte}`,
`<b>Points de Tâche</b>: ${rddData.points_de_tache}`,
`<b>Encombrement</b>: ${rddData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_potionChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Rareté</b>: ${rddData.rarete}`,
`<b>Catégorie</b>: ${rddData.categorie}`,
`<b>Encombrement</b>: ${rddData.encombrement}`,
]
return properties;
}
/* -------------------------------------------- */
_queueChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Refoulement</b>: ${rddData.refoulement}`
]
return properties;
}
/* -------------------------------------------- */
_ombreChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Refoulement</b>: ${rddData.refoulement}`
]
return properties;
}
/* -------------------------------------------- */
_souffleChatData() {
const rddData = Misc.data(this).data;
let properties = [];
return properties;
}
/* -------------------------------------------- */
_teteChatData() {
const rddData = Misc.data(this).data;
let properties = [];
return properties;
}
/* -------------------------------------------- */
_tarotChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Concept</b>: ${rddData.concept}`,
`<b>Aspect</b>: ${rddData.aspect}`,
]
return properties;
}
/* -------------------------------------------- */
_nombreastralChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Valeur</b>: ${rddData.value}`,
`<b>Jour</b>: ${rddData.jourlabel}`,
]
return properties;
}
/* -------------------------------------------- */
_monnaieChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Valeur en Deniers</b>: ${rddData.valeur_deniers}`,
`<b>Encombrement</b>: ${rddData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_meditationChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Thème</b>: ${rddData.theme}`,
`<b>Compétence</b>: ${rddData.competence}`,
`<b>Support</b>: ${rddData.support}`,
`<b>Heure</b>: ${rddData.heure}`,
`<b>Purification</b>: ${rddData.purification}`,
`<b>Vêture</b>: ${rddData.veture}`,
`<b>Comportement</b>: ${rddData.comportement}`,
`<b>Case TMR</b>: ${rddData.tmr}`
]
return properties;
}
/* -------------------------------------------- */
_casetmrChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Coordonnée</b>: ${rddData.coord}`,
`<b>Spécificité</b>: ${rddData.specific}`
]
return properties;
}
}

View File

@ -1,9 +1,11 @@
import { RdDItemSort } from "./item-sort.js"; import { RdDItemSort } from "./item-sort.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { RdDItem } from "./item-rdd.js";
import { RdDAlchimie } from "./rdd-alchimie.js"; import { RdDAlchimie } from "./rdd-alchimie.js";
import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemCompetence } from "./item-competence.js";
import { RdDHerbes } from "./rdd-herbes.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { HtmlUtility } from "./html-utility.js";
import { ReglesOptionelles } from "./regles-optionelles.js";
/** /**
* Extend the basic ItemSheet with some very simple modifications * Extend the basic ItemSheet with some very simple modifications
@ -12,85 +14,139 @@ import { Misc } from "./misc.js";
export class RdDItemSheet extends ItemSheet { export class RdDItemSheet extends ItemSheet {
/** @override */ /** @override */
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
classes: ["foundryvtt-reve-de-dragon", "sheet", "item"], classes: ["foundryvtt-reve-de-dragon", "sheet", "item"],
template: "systems/foundryvtt-reve-de-dragon/templates/item-sheet.html", template: "systems/foundryvtt-reve-de-dragon/templates/item-sheet.html",
width: 550, width: 550,
height: 550 height: 550
//tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description"}] //tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description"}]
}); });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_getHeaderButtons() { _getHeaderButtons() {
let buttons = super._getHeaderButtons(); let buttons = super._getHeaderButtons();
const videSiConteneur = this.object.isConteneur() ? this.object.isVide() : true;
// Add "Post to chat" button // Add "Post to chat" button
// We previously restricted this to GM and editable items only. If you ever find this comment because it broke something: eh, sorry! // We previously restricted this to GM and editable items only. If you ever find this comment because it broke something: eh, sorry!
buttons.unshift( if ("cout" in Misc.templateData(this.object) && videSiConteneur) {
{ buttons.unshift({
class: "post",
icon: "fas fa-comments-dollar",
onclick: ev => this.item.proposerVente()
});
}
else {
buttons.unshift({
class: "post", class: "post",
icon: "fas fa-comment", icon: "fas fa-comment",
onclick: ev => new RdDItem(Misc.data(this.item)).postItem() onclick: ev => this.item.postItem()
}) });
}
return buttons return buttons
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
setPosition(options={}) { setPosition(options = {}) {
const position = super.setPosition(options); const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetBody = this.element.find(".sheet-body"); const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - 192; const bodyHeight = position.height - sheetHeader[0].clientHeight;
sheetBody.css("height", bodyHeight); sheetBody.css("height", bodyHeight);
return position; return position;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async getData() { async getData() {
let formData = super.getData(); const objectData = Misc.data(this.object);
formData.categorieCompetences = RdDItemCompetence.getCategorieCompetences();
if ( formData.item.type == 'tache' || formData.item.type == 'livre' || formData.item.type == 'meditation' || formData.item.type == 'oeuvre') { let formData = {
formData.caracList = duplicate(game.system.model.Actor.personnage.carac); title: objectData.name,
formData.competences = await RdDUtility.loadCompendiumNames( 'foundryvtt-reve-de-dragon.competences' ); id: objectData.id,
type: objectData.type,
img: objectData.img,
name: objectData.name,
data: objectData.data,
isGM: game.user.isGM,
owner: this.document.isOwner,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
isSoins: false
} }
if (formData.item.type == 'arme') { if (this.actor) {
formData.competences = await RdDUtility.loadCompendium( 'foundryvtt-reve-de-dragon.competences', it => RdDItemCompetence.isCompetenceArme(it));
}
if ( formData.item.type == 'recettealchimique' ) {
RdDAlchimie.processManipulation(formData.item, this.actor && this.actor._id );
}
if ( this.actor ) {
formData.isOwned = true; formData.isOwned = true;
formData.actorId = this.actor._id; formData.actorId = this.actor.id;
}
formData.categorieCompetences = RdDItemCompetence.getCategorieCompetences();
if (formData.type == 'tache' || formData.type == 'livre' || formData.type == 'meditation' || formData.type == 'oeuvre') {
formData.caracList = duplicate(game.system.model.Actor.personnage.carac);
formData.competences = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.competences');
}
if (formData.type == 'arme') {
formData.competences = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.competences', it => RdDItemCompetence.isCompetenceArme(it));
console.log(formData.competences);
}
if (formData.type == 'recettealchimique') {
RdDAlchimie.processManipulation(objectData, this.actor && this.actor.id);
}
if (formData.type == 'potion') {
if (this.dateUpdated) {
formData.data.prdate = this.dateUpdated;
this.dateUpdated = undefined;
}
RdDHerbes.updatePotionData(formData);
}
if (formData.isOwned && formData.type == 'herbe' && (formData.data.categorie == 'Soin' || formData.data.categorie == 'Repos')) {
formData.isIngredientPotionBase = true;
} }
formData.bonusCaseList = RdDItemSort.getBonusCaseList(formData, true); formData.bonusCaseList = RdDItemSort.getBonusCaseList(formData, true);
formData.isGM = game.user.isGM; // Pour verrouiller certaines éditions
return formData; return formData;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
HtmlUtility._showControlWhen($(".item-cout"), ReglesOptionelles.isUsing('afficher-prix-joueurs') || game.user.isGM || !this.object.isOwned);
HtmlUtility._showControlWhen($(".item-magique"), this.object.isMagique());
// Everything below here is only needed if the sheet is editable // Everything below here is only needed if the sheet is editable
if (!this.options.editable) return; if (!this.options.editable) return;
// Select competence categorie // Select competence categorie
html.find("#categorie").on("click", this._onClickSelectCategorie.bind(this) ); html.find(".categorie").change(event => this._onSelectCategorie(event));
html.find('#sheet-competence-xp').change((event) => { html.find('.sheet-competence-xp').change((event) => {
if ( this.object.data.type == 'competence') { if (this.object.data.type == 'competence') {
RdDUtility.checkThanatosXP( this.object.data.name ); RdDUtility.checkThanatosXP(this.object.data.name);
} }
} ); });
html.find('#creer-tache-livre').click((event) => { html.find('.enchanteDate').change((event) => {
let jour = Number($('#jourMois').val());
let mois = $('#nomMois').val();
this.dateUpdated = game.system.rdd.calendrier.getIndexFromDate(jour, mois);
});
html.find('.creer-tache-livre').click((event) => {
let actorId = event.currentTarget.attributes['data-actor-id'].value; let actorId = event.currentTarget.attributes['data-actor-id'].value;
let actor = game.actors.get( actorId ); let actor = game.actors.get(actorId);
actor.creerTacheDepuisLivre( this.item ); actor.creerTacheDepuisLivre(this.item);
});
html.find('.consommer-potion').click((event) => {
let actorId = event.currentTarget.attributes['data-actor-id'].value;
let actor = game.actors.get(actorId);
actor.consommerPotion(this.item);
});
html.find('.creer-potion-base').click((event) => {
let actorId = event.currentTarget.attributes['data-actor-id'].value;
let actor = game.actors.get(actorId);
actor.dialogFabriquerPotion(this.item);
}); });
html.find('.alchimie-tache a').click((event) => { html.find('.alchimie-tache a').click((event) => {
@ -98,39 +154,42 @@ export class RdDItemSheet extends ItemSheet {
let recetteId = event.currentTarget.attributes['data-recette-id'].value; let recetteId = event.currentTarget.attributes['data-recette-id'].value;
let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value; let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value;
let tacheData = event.currentTarget.attributes['data-alchimie-data'].value; let tacheData = event.currentTarget.attributes['data-alchimie-data'].value;
let actor = game.actors.get( actorId ); let actor = game.actors.get(actorId);
if ( actor ) { if (actor) {
actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData); actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData);
} else { } else {
ui.notifications.info("Impossible trouver un actur pour réaliser cette tache Alchimique."); ui.notifications.info("Impossible trouver un actur pour réaliser cette tache Alchimique.");
} }
}); });
}
/* -------------------------------------------- */
async _onClickSelectCategorie(event) {
event.preventDefault();
let level = RdDItemCompetence.getNiveauBase(event.currentTarget.value);
this.object.data.data.base = level;
$("#base").val( level );
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
get template() async _onSelectCategorie(event) {
{ event.preventDefault();
let type = this.item.type;
if (this.object.isCompetence()){
let level = RdDItemCompetence.getNiveauBase(event.currentTarget.value);
Misc.templateData(this.object).base = level;
$("#base").val(level);
}
}
/* -------------------------------------------- */
get template() {
//console.log(this);
let type = this.object.data.type;
return `systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html`; return `systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html`;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
_updateObject(event, formData) { _updateObject(event, formData) { // Deprecated en v0.8 à clarifier
//console.log("UPDATE !", formData);
// Données de bonus de cases ? // Données de bonus de cases ?
formData = RdDItemSort.buildBonusCaseStringFromFormData( formData ); formData = RdDItemSort.buildBonusCaseStringFromFormData(formData);
return this.object.update(formData); return this.object.update(formData);
} }
} }

View File

@ -0,0 +1,104 @@
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
import { Misc } from "./misc.js";
import { TMRType, TMRUtility } from "./tmr-utility.js";
/**
* Item sheet pour signes draconiques
* @extends {ItemSheet}
*/
export class RdDSigneDraconiqueItemSheet extends ItemSheet {
/** @override */
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
classes: ["foundryvtt-reve-de-dragon", "sheet", "item"],
template: "systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html",
width: 550,
height: 550
});
}
/* -------------------------------------------- */
_getHeaderButtons() {
let buttons = super._getHeaderButtons();
buttons.unshift({ class: "post", icon: "fas fa-comment", onclick: ev => this.item.postItem() });
return buttons;
}
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - sheetHeader[0].clientHeight;
sheetBody.css("height", bodyHeight);
return position;
}
/* -------------------------------------------- */
async getData() {
const formData = duplicate(Misc.data(this.object));
mergeObject(formData, {
title: formData.name,
isGM: game.user.isGM,
owner: this.document.isOwner,
isOwned: this.actor ? true : false,
actorId: this.actor?.id,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
});
formData.tmrs = TMRUtility.listSelectedTMR(formData.data.typesTMR ?? []);
return formData;
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
if (!this.options.editable) return;
html.find(".signe-aleatoire").click(event => this.setSigneAleatoire());
html.find(".select-tmr").change((event) => this.onSelectTmr(event));
html.find(".signe-xp-sort").change((event) => this.onValeurXpSort(event.currentTarget.attributes['data-typereussite']?.value, Number(event.currentTarget.value)));
}
async setSigneAleatoire() {
const newSigne = await RdDItemSigneDraconique.randomSigneDraconique();
// $("[name='signe.name']").val(newSigne.name);
// $("[name='signe.data.valeur.norm']").val(newSigne.data.valeur.norm);
// $("[name='signe.data.valeur.sign']").val(newSigne.data.valeur.sign);
// $("[name='signe.data.valeur.part']").val(newSigne.data.valeur.part);
// $("[name='signe.data.difficulte']").val(newSigne.data.difficulte);
// $("[name='signe.data.duree']").val(newSigne.data.duree);
// $("[name='signe.data.ephemere']").prop("checked", newSigne.data.ephemere);
// $(".select-tmr").val(newSigne.data.typesTMR);
// this.setEphemere(newSigne.data.ephemere);
this.object.update(newSigne);
}
async onSelectTmr(event) {
event.preventDefault();
const selectedTMR = $(".select-tmr").val();
this.object.update({ 'data.typesTMR': selectedTMR });
}
async onValeurXpSort(event) {
const codeReussite = event.currentTarget.attributes['data-typereussite']?.value ?? 0;
const xp = Number(event.currentTarget.value);
const oldValeur = Misc.templateData(this.object).valeur;
const newValeur = RdDItemSigneDraconique.calculValeursXpSort(codeReussite, xp, oldValeur);
await this.object.update({ 'data.valeur': newValeur });
}
/* -------------------------------------------- */
get template() {
return `systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html`;
}
get title() {
return `Signe draconique: ${this.object.name}`;
}
}

View File

@ -0,0 +1,100 @@
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
import { RdDRollTables } from "./rdd-rolltables.js";
import { TMRType } from "./tmr-utility.js";
const tableSignesIndicatifs = [
{ rarete: "Très facile", difficulte: 0, xp: 6, nbCases: 14 },
{ rarete: "Facile", difficulte: -2, xp: 10, nbCases: 10 },
{ rarete: "Moyen", difficulte: -3, xp: 15, nbCases: 7 },
{ rarete: "Difficile", difficulte: -5, xp: 20, nbCases: 4 },
{ rarete: "Ardu", difficulte: -8, xp: 30, nbCases: 1 }
]
export class RdDItemSigneDraconique {
static prepareSigneDraconiqueMeditation(meditation, rolled) {
if (rolled.isSuccess != undefined) {
meditation = Misc.data(meditation);
return {
name: "de la " + meditation.name,
type: "signedraconique",
img: meditation.img,
data: {
"typesTMR": [Misc.upperFirst(meditation.data.tmr)],
"difficulte": RdDItemSigneDraconique.getDiffSigneMeditation(rolled.code),
"ephemere": true,
"duree": "1 round",
"valeur": { "norm": 3, "sign": 5, "part": 10 }
}
};
}
return undefined;
}
static getDiffSigneMeditation(code) {
switch (code) {
case "norm": return -7;
case "sign": return -3;
case "part": return 0;
}
return undefined;
}
static getXpSortSigneDraconique(code, signe) {
return Misc.data(signe).data.valeur[code] ?? 0;
}
static calculValeursXpSort(qualite, valeur, avant) {
switch (qualite) {
case "norm":
return {
norm: valeur,
sign: Math.max(valeur, avant.sign),
part: Math.max(valeur, avant.part)
}
case "sign":
return {
norm: Math.min(valeur, avant.norm),
sign: valeur,
part: Math.max(valeur, avant.part)
}
case "part":
return {
norm: Math.min(valeur, avant.norm),
sign: Math.min(valeur, avant.sign),
part: valeur
}
}
}
static async randomSigneDraconique() {
let modele = await RdDDice.rollOneOf(tableSignesIndicatifs);
return {
name: await RdDItemSigneDraconique.randomSigneDescription(),
type: "signedraconique",
img: 'systems/foundryvtt-reve-de-dragon/icons/tmr/signe_draconique.webp',
data: {
typesTMR: await RdDItemSigneDraconique.randomTmrs(modele.nbCases),
ephemere: true,
duree: "1 round",
difficulte: modele.difficulte,
valeur: { norm: modele.xp, sign: modele.xp, part: Math.floor(modele.xp * 1.5) },
}
};
}
static async randomTmrs(nbTmr = undefined) {
let tmrs = Object.values(TMRType).map(value => Misc.upperFirst(value.name));
let keep = nbTmr ?? (await RdDDice.rollTotal("1d" + TMRType.length) + 1);
for (let i = tmrs.length; i > keep; i--) {
tmrs.splice(await RdDDice.rollTotal("1d" + i), 1);
}
return tmrs;
}
static async randomSigneDescription() {
return await RdDRollTables.drawTextFromRollTable("Signes draconiques", false);
}
}

View File

@ -51,10 +51,10 @@ export class RdDItemSort extends Item {
* Retourne une liste de bonus/case pour un item-sheet * Retourne une liste de bonus/case pour un item-sheet
* @param {} item * @param {} item
*/ */
static getBonusCaseList( data, newCase = false ) { static getBonusCaseList( item, newCase = false ) {
// Gestion spéciale case bonus // Gestion spéciale case bonus
if ( data.item.type == 'sort') { if ( item.type == 'sort') {
return this.buildBonusCaseList(data.data.bonuscase, newCase ); return this.buildBonusCaseList(item.data.bonuscase, newCase );
} }
return undefined; return undefined;
} }
@ -106,7 +106,7 @@ export class RdDItemSort extends Item {
// Sauvegarde/update // Sauvegarde/update
let bonuscase = StringList.toString(); let bonuscase = StringList.toString();
//console.log("Bonus cae :", bonuscase); //console.log("Bonus cae :", bonuscase);
actor.updateEmbeddedEntity("OwnedItem", { _id: sort._id, 'data.bonuscase': bonuscase } ); actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'data.bonuscase': bonuscase }] );
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

512
module/item.js Normal file
View File

@ -0,0 +1,512 @@
import { DialogItemVente } from "./dialog-item-vente.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js";
const typesObjetsEquipement = ["objet", "arme", "armure", "conteneur", "herbe", "ingredient", "livre", "potion", "munition", "nourritureboisson", "monnaie"];
const typesObjetsOeuvres = ["oeuvre", "recettecuisine", "musique", "chant", "danse", "jeu"];
const encBrin = 0.00005;// un brin = 1 décigramme = 1/10g = 1/10000kg = 1/20000 enc
/* -------------------------------------------- */
export class RdDItem extends Item {
static getTypeObjetsEquipement() {
return typesObjetsEquipement;
}
static getTypesOeuvres() {
return typesObjetsOeuvres;
}
isCompetence() {
return Misc.data(this).type == 'competence';
}
isConteneur() {
return Misc.data(this).type == 'conteneur';
}
isVide() {
return this.isConteneur() && (Misc.templateData(this).contenu ?? []).length == 0;
}
isAlcool() {
const itemData = Misc.data(this);
return itemData.type == 'nourritureboisson' && itemData.data.boisson && itemData.data.alcoolise;
}
isPotion() {
return Misc.data(this).type == 'potion';
}
isEquipement() {
return RdDItem.getTypeObjetsEquipement().includes(Misc.data(this).type);
}
isCristalAlchimique() {
const itemData = Misc.data(this);
return itemData.type == 'objet' && Grammar.toLowerCaseNoAccent(itemData.name) == 'cristal alchimique' && itemData.data.quantite > 0;
}
isMagique() {
return Misc.templateData(this.object).magique;
}
getEnc() {
const itemData = Misc.data(this);
switch (itemData.type) {
case 'herbe':
return encBrin;
}
return itemData.data.encombrement
}
prepareDerivedData() {
super.prepareDerivedData();
if (this.isEquipement(this)) {
this._calculsEquipement();
}
if (this.isPotion()) {
this.prepareDataPotion()
}
const itemData = Misc.data(this);
itemData.data.actionPrincipale = this.getActionPrincipale({ warnIfNot: false });
}
prepareDataPotion() {
const tplData = Misc.templateData(this);
const categorie = Grammar.toLowerCaseNoAccent(tplData.categorie);
tplData.magique = categorie.includes('enchante');
if (tplData.magique) {
if (categorie.includes('soin') || categorie.includes('repos')) {
tplData.puissance = tplData.herbebonus * tplData.pr;
}
}
}
_calculsEquipement() {
const tplData = Misc.templateData(this);
const quantite = this.isConteneur() ? 1 : (tplData.quantite ?? 0);
const enc = this.getEnc();
if (enc != undefined) {
tplData.encTotal = Math.max(enc, 0) * quantite;
}
if (tplData.cout != undefined) {
tplData.prixTotal = Math.max(tplData.cout, 0) * quantite;
}
}
getActionPrincipale(options = { warnIfNot: true }) {
const itemData = Misc.data(this);
if ((itemData.data.quantite ?? 0) <= 0) {
if (options.warnIfNot) {
ui.notifications.warn(`Vous n'avez plus de ${itemData.name}.`);
}
return undefined;
}
switch (itemData.type) {
case 'nourritureboisson': return itemData.data.boisson ? 'Boire' : 'Manger';
case 'potion': return 'Boire';
case 'livre': return 'Lire';
}
if (options.warnIfNot) {
ui.notifications.warn(`Impossible d'utilise un ${itemData.name}, aucune action associée définie.`);
}
return undefined;
}
async diminuerQuantite(nombre, options = { diminuerQuantite: true, supprimerSiZero: false }) {
if (options.diminuerQuantite == false) return;
await this.quantiteIncDec(-nombre, options);
}
async quantiteIncDec(nombre, options = { diminuerQuantite: true, supprimerSiZero: false }) {
const itemData = Misc.data(this);
const quantite = Number(itemData.data.quantite ?? -1);
if (quantite >= 0) {
const reste = Math.max(quantite + Number(nombre), 0);
if (reste == 0) {
if (options.supprimerSiZero) {
ui.notifications.notify(`${itemData.name} supprimé de votre équipement`);
await this.delete();
}
else {
ui.notifications.notify(`Il ne vous reste plus de ${itemData.name}, vous pouvez le supprimer de votre équipement, ou trouver un moyen de vous en procurer.`);
await this.update({ "data.quantite": 0 });
}
}
else {
await this.update({ "data.quantite": reste });
}
}
}
/* -------------------------------------------- */
// détermine si deux équipements sont similaires: de même type, et avec les même champs hormis la quantité
isEquipementSimilaire(other) {
const itemData = Misc.data(this);
const otherData = Misc.data(other);
const tplData = Misc.templateData(this);
const otherTplData = Misc.templateData(other);
if (!this.isEquipement()) return false;
if (itemData.type != otherData.type) return false;
if (itemData.name != otherData.name) return false;
if (tplData.quantite == undefined) return false;
for (const [key, value] of Object.entries(tplData)) {
if (['quantite', 'encTotal', 'prixTotal', 'cout'].includes(key)) continue;
if (value != otherTplData[key]) return false;
}
return true;
}
async proposerVente() {
console.log(this);
const dialog = await DialogItemVente.create(this, (vente) => this._onProposerVente(vente))
dialog.render(true);
}
async _onProposerVente(venteData) {
venteData["properties"] = this[`_${venteData.item.type}ChatData`]();
if (venteData.isOwned) {
if (venteData.quantiteNbLots * venteData.tailleLot > venteData.quantiteMax) {
ui.notifications.warn(`Vous avez ${venteData.quantiteMax} ${venteData.item.name}, ce n'est pas suffisant pour vendre ${venteData.quantiteNbLots} de ${venteData.tailleLot}`)
return;
}
}
venteData.jsondata = JSON.stringify(venteData.item);
console.log(venteData);
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', venteData);
ChatMessage.create( RdDUtility.chatDataSetup(html));
}
/* -------------------------------------------- */
async postItem() {
console.log(this);
let chatData = duplicate(Misc.data(this));
const properties = this[`_${chatData.type}ChatData`]();
chatData["properties"] = properties
if (this.actor) {
chatData.actor = { id: this.actor.id };
}
//Check if the posted item should have availability/pay buttons
chatData.hasPrice = "cout" in chatData.data;
chatData.data.cout_deniers = 0;
let dialogResult = [-1, -1]; // dialogResult[0] = quantité, dialogResult[1] = prix
if (chatData.hasPrice) {
chatData.data.cout_deniers = Math.floor(chatData.data.cout * 100);
dialogResult = await new Promise((resolve, reject) => {
new Dialog({
content:
`<p>Modifier la quantité?</p>
<div class="form-group">
<label> Quantité</label>
<input name="quantity" type="text" value="1"/>
</div>
<p>Modifier la prix?</p>
<div class="form-group">
<label>Prix en Sols</label>
<input name="price" type="text" value="${chatData.data.cout}"/>
</div>
`,
title: "Quantité & Prix",
buttons: {
post: {
label: "Soumettre",
callback: (dlg) => {
resolve([Number(dlg.find('[name="quantity"]').val()), Number(dlg.find('[name="price"]').val())])
}
},
}
}).render(true)
})
}
let quantiteEnvoi = this.isOwned ? Math.min(dialogResult[0], chatData.data.quantite) : dialogResult[0];
const prixTotal = dialogResult[1];
if (quantiteEnvoi > 0) {
if (this.isOwned) {
if (chatData.data.quantite == 0) {
quantiteEnvoi = -1
}
else if (quantiteEnvoi > chatData.data.quantite) {
quantiteEnvoi = chatData.data.quantite;
ui.notifications.notify(`Impossible de poster plus que ce que vous avez. La quantité à été réduite à ${quantiteEnvoi}.`)
}
if (quantiteEnvoi > 0) {
this.diminuerQuantite(quantiteEnvoi);
}
}
}
if (chatData.hasPrice) {
if (quantiteEnvoi > 0)
chatData.postQuantity = Number(quantiteEnvoi);
if (prixTotal >= 0) {
chatData.postPrice = prixTotal;
chatData.data.cout_deniers = Math.floor(prixTotal * 100); // Mise à jour cout en deniers
}
chatData.finalPrice = Number(chatData.postPrice) * Number(chatData.postQuantity);
chatData.data.cout_deniers_total = chatData.data.cout_deniers * Number(chatData.postQuantity);
chatData.data.quantite = chatData.postQuantity;
console.log("POST : ", chatData.finalPrice, chatData.data.cout_deniers_total, chatData.postQuantity);
}
// Don't post any image for the item (which would leave a large gap) if the default image is used
if (chatData.img.includes("/blank.png"))
chatData.img = null;
// JSON object for easy creation
chatData.jsondata = JSON.stringify(
{
compendium: "postedItem",
payload: chatData,
});
renderTemplate('systems/foundryvtt-reve-de-dragon/templates/post-item.html', chatData).then(html => {
let chatOptions = RdDUtility.chatDataSetup(html);
ChatMessage.create(chatOptions)
});
}
static propertyIfDefined(name, val, condition = (it) => true) {
return condition ? [`<b>${name}</b>: ${val}`] : [];
}
/* -------------------------------------------- */
_objetChatData() {
const tplData = Misc.templateData(this);
let properties = [].concat(
RdDItem.propertyIfDefined('Résistance', tplData.resistance, tplData.resistance),
RdDItem.propertyIfDefined('Qualité', tplData.qualite, tplData.qualite),
RdDItem.propertyIfDefined('Encombrement', tplData.encombrement),
);
return properties;
}
/* -------------------------------------------- */
_nourritureboissonChatData() {
const tplData = Misc.templateData(this);
let properties = [].concat(
RdDItem.propertyIfDefined('Sustentation', tplData.sust, tplData.sust > 0),
RdDItem.propertyIfDefined('Désaltère', tplData.desaltere, tplData.boisson),
RdDItem.propertyIfDefined('Force alcool', tplData.force, tplData.boisson && tplData.alcoolise),
RdDItem.propertyIfDefined('Exotisme', tplData.exotisme, tplData.exotisme < 0),
RdDItem.propertyIfDefined('Qualité', tplData.qualite, tplData.qualite),
RdDItem.propertyIfDefined('Encombrement', tplData.encombrement),
);
return properties;
}
/* -------------------------------------------- */
_armeChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Compétence</b>: ${tplData.competence}`,
`<b>Dommages</b>: ${tplData.dommages}`,
`<b>Force minimum</b>: ${tplData.force}`,
`<b>Resistance</b>: ${tplData.resistance}`,
`<b>Encombrement</b>: ${tplData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_conteneurChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Capacité</b>: ${tplData.capacite} Enc.`,
`<b>Encombrement</b>: ${tplData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_munitionChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Encombrement</b>: ${tplData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_armureChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Protection</b>: ${tplData.protection}`,
`<b>Détérioration</b>: ${tplData.deterioration}`,
`<b>Malus armure</b>: ${tplData.malus}`,
`<b>Encombrement</b>: ${tplData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_competenceChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Catégorie</b>: ${tplData.categorie}`,
`<b>Niveau</b>: ${tplData.niveau}`,
`<b>Caractéristique par défaut</b>: ${tplData.carac_defaut}`,
`<b>XP</b>: ${tplData.xp}`
]
return properties;
}
/* -------------------------------------------- */
_competencecreatureChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Catégorie</b>: ${tplData.categorie}`,
`<b>Niveau</b>: ${tplData.niveau}`,
`<b>Caractéristique</b>: ${tplData.carac_value}`,
`<b>XP</b>: ${tplData.xp}`
]
return properties;
}
/* -------------------------------------------- */
_sortChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Draconic</b>: ${tplData.draconic}`,
`<b>Difficulté</b>: ${tplData.difficulte}`,
`<b>Case TMR</b>: ${tplData.caseTMR}`,
`<b>Points de Rêve</b>: ${tplData.ptreve}`
]
return properties;
}
/* -------------------------------------------- */
_herbeChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Milieu</b>: ${tplData.milieu}`,
`<b>Rareté</b>: ${tplData.rarete}`,
`<b>Catégorie</b>: ${tplData.categorie}`,
]
return properties;
}
/* -------------------------------------------- */
_ingredientChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Milieu</b>: ${tplData.milieu}`,
`<b>Rareté</b>: ${tplData.rarete}`,
`<b>Catégorie</b>: ${tplData.categorie}`,
]
return properties;
}
/* -------------------------------------------- */
_tacheChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Caractéristique</b>: ${tplData.carac}`,
`<b>Compétence</b>: ${tplData.competence}`,
`<b>Périodicité</b>: ${tplData.periodicite}`,
`<b>Fatigue</b>: ${tplData.fatigue}`,
`<b>Difficulté</b>: ${tplData.difficulte}`,
`<b>Points de Tâche</b>: ${tplData.points_de_tache}`,
`<b>Points de Tâche atteints</b>: ${tplData.points_de_tache_courant}`
]
return properties;
}
/* -------------------------------------------- */
_livreChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Compétence</b>: ${tplData.competence}`,
`<b>Auteur</b>: ${tplData.auteur}`,
`<b>Difficulté</b>: ${tplData.difficulte}`,
`<b>Points de Tâche</b>: ${tplData.points_de_tache}`,
`<b>Encombrement</b>: ${tplData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_potionChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Rareté</b>: ${tplData.rarete}`,
`<b>Catégorie</b>: ${tplData.categorie}`,
`<b>Encombrement</b>: ${tplData.encombrement}`,
]
return properties;
}
/* -------------------------------------------- */
_queueChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Refoulement</b>: ${tplData.refoulement}`
]
return properties;
}
/* -------------------------------------------- */
_ombreChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Refoulement</b>: ${tplData.refoulement}`
]
return properties;
}
/* -------------------------------------------- */
_souffleChatData() {
const tplData = Misc.templateData(this);
let properties = [];
return properties;
}
/* -------------------------------------------- */
_teteChatData() {
const tplData = Misc.templateData(this);
let properties = [];
return properties;
}
/* -------------------------------------------- */
_tarotChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Concept</b>: ${tplData.concept}`,
`<b>Aspect</b>: ${tplData.aspect}`,
]
return properties;
}
/* -------------------------------------------- */
_nombreastralChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Valeur</b>: ${tplData.value}`,
`<b>Jour</b>: ${tplData.jourlabel}`,
]
return properties;
}
/* -------------------------------------------- */
_monnaieChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Valeur en Deniers</b>: ${tplData.valeur_deniers}`,
`<b>Encombrement</b>: ${tplData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_meditationChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Thème</b>: ${tplData.theme}`,
`<b>Compétence</b>: ${tplData.competence}`,
`<b>Support</b>: ${tplData.support}`,
`<b>Heure</b>: ${tplData.heure}`,
`<b>Purification</b>: ${tplData.purification}`,
`<b>Vêture</b>: ${tplData.veture}`,
`<b>Comportement</b>: ${tplData.comportement}`,
`<b>Case TMR</b>: ${tplData.tmr}`
]
return properties;
}
/* -------------------------------------------- */
_casetmrChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Coordonnée</b>: ${tplData.coord}`,
`<b>Spécificité</b>: ${tplData.specific}`
]
return properties;
}
}

View File

@ -1,3 +1,4 @@
import { RdDDice } from "./rdd-dice.js";
/** /**
* This class is intended as a placeholder for utility methods unrelated * This class is intended as a placeholder for utility methods unrelated
@ -18,6 +19,24 @@ export class Misc {
return isPositiveNumber ? "+" + number : number return isPositiveNumber ? "+" + number : number
} }
static sum() {
return (a, b) => a + b;
}
static ascending(orderFunction = x => x) {
return (a, b) => Misc.sortingBy(orderFunction(a), orderFunction(b));
}
static descending(orderFunction = x => x) {
return (a, b) => Misc.sortingBy(orderFunction(b), orderFunction(a));
}
static sortingBy(a, b) {
if (a > b) return 1;
if (a < b) return -1;
return 0;
}
/** /**
* Converts the value to an integer, or to 0 if undefined/null/not representing integer * Converts the value to an integer, or to 0 if undefined/null/not representing integer
* @param {*} value value to convert to an integer using parseInt * @param {*} value value to convert to an integer using parseInt
@ -30,6 +49,12 @@ export class Misc {
return isNaN(parsed) ? 0 : parsed; return isNaN(parsed) ? 0 : parsed;
} }
static keepDecimals(num, decimals) {
if (decimals <= 0 || decimals > 6) return num;
const decimal = Math.pow(10, parseInt(decimals));
return Math.round(num * decimal) / decimal;
}
static getFractionHtml(diviseur) { static getFractionHtml(diviseur) {
if (!diviseur || diviseur <= 1) return undefined; if (!diviseur || diviseur <= 1) return undefined;
switch (diviseur || 1) { switch (diviseur || 1) {
@ -39,9 +64,9 @@ export class Misc {
} }
} }
static classify(items, classifier = it => it.type, transform = it => it) { static classify(items, classifier = it => it.type) {
let itemsBy = {}; let itemsBy = {};
Misc.classifyInto(itemsBy, items, classifier, transform); Misc.classifyInto(itemsBy, items, classifier);
return itemsBy; return itemsBy;
} }
@ -56,7 +81,7 @@ export class Misc {
return itemsBy; return itemsBy;
} }
static classifyInto(itemsBy, items, classifier = it => it.type, transform = it => it) { static classifyInto(itemsBy, items, classifier = it => it.type) {
for (const item of items) { for (const item of items) {
const classification = classifier(item); const classification = classifier(item);
let list = itemsBy[classification]; let list = itemsBy[classification];
@ -64,31 +89,16 @@ export class Misc {
list = []; list = [];
itemsBy[classification] = list; itemsBy[classification] = list;
} }
list.push(transform(item)); list.push(item);
} }
} }
static rollOneOf(array) {
return array[new Roll("1d" + array.length).evaluate().total - 1];
}
static distinct(array) { static distinct(array) {
return [...new Set(array)]; return [...new Set(array)];
} }
static actorData(actor) {
return Misc.data(actor);
}
static itemData(item) {
return Misc.data(item);
}
static data(it) { static data(it) {
if (it instanceof Item) { if (it instanceof Actor || it instanceof Item || it instanceof Combatant) {
return it.data;
}
if (it instanceof Actor) {
return it.data; return it.data;
} }
return it; return it;
@ -97,4 +107,14 @@ export class Misc {
static templateData(it) { static templateData(it) {
return Misc.data(it)?.data ?? {} return Misc.data(it)?.data ?? {}
} }
static connectedGMOrUser(ownerId = undefined) {
if (ownerId && game.user.id == ownerId) {
return ownerId;
}
return (game.user.isGM ? game.user.id : game.users.entities.find(u => u.isGM && u.active)?.id) ?? game.user.id;
}
static isElectedUser() {
return game.user.id == Misc.connectedGMOrUser();
}
} }

View File

@ -1,4 +1,5 @@
import { Misc } from "./misc.js" import { Misc } from "./misc.js"
import { RdDDice } from "./rdd-dice.js";
const poesieHautReve = [ const poesieHautReve = [
{ {
@ -50,7 +51,7 @@ const poesieHautReve = [
}, },
{ {
reference: 'Denis Gerfaud', reference: 'Denis Gerfaud',
extrait: `Ainsi se cuccèdent les Jours et les Ages. extrait: `Ainsi se succèdent les Jours et les Ages.
<br>Les jours des Dragons sont les Ages des Hommes.` <br>Les jours des Dragons sont les Ages des Hommes.`
}, },
{ {
@ -64,8 +65,8 @@ const poesieHautReve = [
] ]
export class Poetique { export class Poetique {
static getExtrait(){ static async getExtrait(){
return Misc.rollOneOf(poesieHautReve); return await RdDDice.rollOneOf(poesieHautReve);
} }
} }

View File

@ -1,68 +1,65 @@
/* -------------------------------------------- */ /* -------------------------------------------- */
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
const matchOperations = new RegExp(/@(\w*){([\w\-]+)}/ig);
const matchOperationTerms = new RegExp(/@(\w*){([\w\-]+)}/i);
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDAlchimie { export class RdDAlchimie {
/* -------------------------------------------- */ /* -------------------------------------------- */
static processManipulation( recette, actorId = undefined ) { static processManipulation(recetteData, actorId = undefined) {
//console.log("CALLED", recette, recette.isOwned, actorId ); //console.log("CALLED", recette, recette.isOwned, actorId );
let manip = duplicate(recette.data.manipulation); let manip = recetteData.data.manipulation;
let reg1 = new RegExp(/@(\w*){([\w\-]+)}/ig); let matchArray = manip.match(matchOperations);
let matchArray = manip.match( reg1 ); if (matchArray) {
if ( matchArray ) { for (let matchStr of matchArray) {
for( let matchStr of matchArray) { let result = matchStr.match(matchOperationTerms);
let reg2 = new RegExp(/@(\w*){([\w\-]+)}/i);
let result = matchStr.match(reg2);
//console.log("RESULT ", result); //console.log("RESULT ", result);
if ( result[1] && result[2]) { if (result[1] && result[2]) {
let commande = Misc.upperFirst( result[1] ); let commande = Misc.upperFirst(result[1]);
let replacement = this[`_alchimie${commande}`](recette, result[2], actorId); let replacement = this[`_alchimie${commande}`](recetteData, result[2], actorId);
manip = manip.replace( result[0], replacement); manip = manip.replace(result[0], replacement);
} }
} }
} }
recette.data.manipulation_update = manip; recetteData.data.manipulation_update = manip;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static _alchimieCouleur( recette, couleurs, actorId ) { static _alchimieCouleur(recette, couleurs, actorId) {
let replacement if (actorId) {
if ( actorId ) { return `<span class="alchimie-tache"><a data-recette-id="${recette._id}" data-actor-id="${actorId}" data-alchimie-tache="couleur" data-alchimie-data="${couleurs}">couleur ${couleurs}</a></span>`;
replacement = `<span class="alchimie-tache"><a data-recette-id="${recette._id}" data-actor-id="${actorId}" data-alchimie-tache="couleur" data-alchimie-data="${couleurs}">couleur ${couleurs}</a></span>`;
} else { } else {
replacement = `<span class="alchimie-tache">couleur ${couleurs} </span>`; return `<span class="alchimie-tache">couleur ${couleurs} </span>`;
} }
return replacement;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static _alchimieConsistance( recette, consistances, actorId ) { static _alchimieConsistance(recette, consistances, actorId) {
let replacement if (actorId) {
if ( actorId ) { return `<span class="alchimie-tache"><a data-recette-id="${recette._id}" data-actor-id="${actorId}" data-alchimie-tache="consistance" data-alchimie-data="${consistances}">consistance ${consistances}</a></span>`;
replacement = `<span class="alchimie-tache"><a data-recette-id="${recette._id}" data-actor-id="${actorId}" data-alchimie-tache="consistance" data-alchimie-data="${consistances}">consistance ${consistances}</a></span>`;
} else { } else {
replacement = `<span class="alchimie-tache">consistance ${consistances} </span>`; return `<span class="alchimie-tache">consistance ${consistances} </span>`;
} }
return replacement;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getDifficulte( aspects ) { static getDifficulte(aspects) {
let aspectsArray = aspects.split('-'); let elements = aspects.split('-');
let diff = 0; let composantes = elements.length;
let nbDifferent = 0; let distincts = Object.keys(Misc.classifyFirst(elements, it => it)).length;
let aspectsHash = {} if (distincts == 1) {
for (let colconst of aspectsArray) { composantes--;
if ( aspectsHash[colconst] ){ // Deja present, augmente difficulté de 1
diff -= 1;
} else {
nbDifferent++;
aspectsHash[colconst] = colconst; // Keep track
}
} }
diff = diff - ((nbDifferent>1) ? nbDifferent : 0); // Ca doit marcher .... return Math.min(0, -composantes);
return Math.min(0, diff); // Pour être sur
} }
static getCaracTache(tache) {
switch (tache) {
case "consistance": return 'dexterite';
case "couleur": return 'vue';
}
return 'intellect';
}
} }

View File

@ -3,12 +3,13 @@
* Extend the base Dialog entity by defining a custom window to perform roll. * Extend the base Dialog entity by defining a custom window to perform roll.
* @extends {Dialog} * @extends {Dialog}
*/ */
export class RdDAstrologieEditeur extends Dialog { export class RdDAstrologieEditeur extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(html, calendrier, calendrierData) { constructor(html, calendrier, calendrierData) {
let myButtons = { let myButtons = {
resetButton: { label: "Re-tirer les nombres astraux", callback: html => this.resetNombreAstraux() },
saveButton: { label: "Fermer", callback: html => this.fillData() } saveButton: { label: "Fermer", callback: html => this.fillData() }
}; };
@ -21,7 +22,15 @@ export class RdDAstrologieEditeur extends Dialog {
this.updateData( calendrierData ); this.updateData( calendrierData );
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
resetNombreAstraux() {
game.system.rdd.calendrier.resetNombreAstral();
game.system.rdd.calendrier.rebuildListeNombreAstral();
game.system.rdd.calendrier.showAstrologieEditor();
}
/* -------------------------------------------- */
fillData( ) { fillData( ) {
} }

View File

@ -8,50 +8,51 @@ import { Misc } from "./misc.js";
*/ */
export class RdDAstrologieJoueur extends Dialog { export class RdDAstrologieJoueur extends Dialog {
/* -------------------------------------------- */
static async create(actor, dialogConfig) {
let data = { nombres: this.organizeNombres( actor),
dates: game.system.rdd.calendrier.getJoursSuivants( 10 ),
etat: actor.getEtatGeneral(),
ajustementsConditions: CONFIG.RDD.ajustementsConditions,
astrologie: RdDItemCompetence.findCompetence( actor.data.items, 'Astrologie')
}
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-astrologie-joueur.html', data);
let options = { classes: ["rdddialog"], width: 600, height: 500, 'z-index': 99999 };
if (dialogConfig.options) {
mergeObject(options, dialogConfig.options, { overwrite: true });
}
return new RdDAstrologieJoueur(html, actor, data);
}
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(html, actor, data ) { static async create(actor, dialogConfig) {
let data = {
nombres: this.organizeNombres(actor),
dates: game.system.rdd.calendrier.getJoursSuivants(10),
etat: actor.getEtatGeneral(),
ajustementsConditions: CONFIG.RDD.ajustementsConditions,
astrologie: RdDItemCompetence.findCompetence(actor.data.items, 'Astrologie')
}
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-astrologie-joueur.html', data);
let options = { classes: ["rdddialog"], width: 600, height: 500, 'z-index': 99999 };
if (dialogConfig.options) {
mergeObject(options, dialogConfig.options, { overwrite: true });
}
return new RdDAstrologieJoueur(html, actor, data);
}
/* -------------------------------------------- */
constructor(html, actor, data) {
let myButtons = { let myButtons = {
saveButton: { label: "Fermer", callback: html => this.quitDialog() } saveButton: { label: "Fermer", callback: html => this.quitDialog() }
}; };
// Get all n // Get all n
// Common conf // Common conf
let dialogConf = { content: html, title: "Nombres Astraux", buttons: myButtons, default: "saveButton" }; let dialogConf = { content: html, title: "Nombres Astraux", buttons: myButtons, default: "saveButton" };
let dialogOptions = { classes: ["rdddialog"], width: 600, height: 300, 'z-index': 99999 } ; let dialogOptions = { classes: ["rdddialog"], width: 600, height: 300, 'z-index': 99999 };
super(dialogConf, dialogOptions); super(dialogConf, dialogOptions);
this.actor = actor; this.actor = actor;
this.dataNombreAstral = duplicate(data); this.dataNombreAstral = duplicate(data);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static organizeNombres(actor) { static organizeNombres(actor) {
let itemNombres = actor.data.items.filter( (item) => item.type == 'nombreastral'); let itemNombres = actor.listItemsData('nombreastral');
let itemFiltered = {}; let itemFiltered = {};
for ( let item of itemNombres) { for (let item of itemNombres) {
if ( itemFiltered[item.data.jourindex] ) { if (itemFiltered[item.data.jourindex]) {
itemFiltered[item.data.jourindex].listValues.push(item.data.value); itemFiltered[item.data.jourindex].listValues.push(item.data.value);
} else { } else {
itemFiltered[item.data.jourindex] = { itemFiltered[item.data.jourindex] = {
listValues: [ item.data.value ], listValues: [item.data.value],
jourlabel: item.data.jourlabel jourlabel: item.data.jourlabel
} }
} }
@ -60,21 +61,22 @@ export class RdDAstrologieJoueur extends Dialog {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
requestJetAstrologie( ) { requestJetAstrologie() {
let data = { id: this.actor.data._id, let data = {
carac_vue: Misc.data(this.actor).data.carac['vue'].value, id: this.actor.data._id,
etat: this.dataNombreAstral.etat, carac_vue: Misc.data(this.actor).data.carac['vue'].value,
astrologie: this.dataNombreAstral.astrologie, etat: this.dataNombreAstral.etat,
conditions: $("#diffConditions").val(), astrologie: this.dataNombreAstral.astrologie,
date: $("#joursAstrologie").val() conditions: $("#diffConditions").val(),
} date: $("#joursAstrologie").val()
if ( game.user.isGM) { }
game.system.rdd.calendrier.requestNombreAstral( data ); if (game.user.isGM) {
game.system.rdd.calendrier.requestNombreAstral(data);
} else { } else {
game.socket.emit("system.foundryvtt-reve-de-dragon", { game.socket.emit("system.foundryvtt-reve-de-dragon", {
msg: "msg_request_nombre_astral", msg: "msg_request_nombre_astral",
data: data data: data
} ); });
} }
this.close(); this.close();
} }
@ -87,7 +89,7 @@ export class RdDAstrologieJoueur extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
$(function () { $(function () {
$("#diffConditions").val(0); $("#diffConditions").val(0);
}); });

View File

@ -5,15 +5,17 @@ import { HtmlUtility } from "./html-utility.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import {RdDDice } from "./rdd-dice.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
const dossierIconesHeures = 'systems/foundryvtt-reve-de-dragon/icons/heures/' const dossierIconesHeures = 'systems/foundryvtt-reve-de-dragon/icons/heures/'
const heuresList = ["vaisseau", "sirene", "faucon", "couronne", "dragon", "epees", "lyre", "serpent", "poissonacrobate", "araignee", "roseau", "chateaudormant"]; const heuresList = ["vaisseau", "sirene", "faucon", "couronne", "dragon", "epees", "lyre", "serpent", "poissonacrobate", "araignee", "roseau", "chateaudormant"];
const heuresDef = { const heuresDef = {
"vaisseau": { label: "Vaisseau", lettreFont: 'v', saison: "printemps", heure: 0, icon: 'hd01.svg' }, "vaisseau": { label: "Vaisseau", lettreFont: 'v', saison: "printemps", heure: 0, icon: 'hd01.svg' },
"sirene": { label: "Sirène", lettreFont: 'S', saison: "printemps", heure: 1, icon: 'hd02.svg' }, "sirene": { label: "Sirène", lettreFont: 'i', saison: "printemps", heure: 1, icon: 'hd02.svg' },
"faucon": { label: "Faucon", lettreFont: 'f', saison: "printemps", heure: 2, icon: 'hd03.svg' }, "faucon": { label: "Faucon", lettreFont: 'f', saison: "printemps", heure: 2, icon: 'hd03.svg' },
"couronne": { label: "Couronne", lettreFont: 'C', saison: "ete", heure: 3, icon: 'hd04.svg' }, "couronne": { label: "Couronne", lettreFont: '', saison: "ete", heure: 3, icon: 'hd04.svg' },
"dragon": { label: "Dragon", lettreFont: 'd', saison: "ete", heure: 4, icon: 'hd05.svg' }, "dragon": { label: "Dragon", lettreFont: 'd', saison: "ete", heure: 4, icon: 'hd05.svg' },
"epees": { label: "Epées", lettreFont: 'e', saison: "ete", heure: 5, icon: 'hd06.svg' }, "epees": { label: "Epées", lettreFont: 'e', saison: "ete", heure: 5, icon: 'hd06.svg' },
"lyre": { label: "Lyre", lettreFont: 'l', saison: "automne", heure: 6, icon: 'hd07.svg' }, "lyre": { label: "Lyre", lettreFont: 'l', saison: "automne", heure: 6, icon: 'hd07.svg' },
@ -39,8 +41,9 @@ export class RdDCalendrier extends Application {
async initCalendrier() { async initCalendrier() {
// Calendrier // Calendrier
this.calendrier = duplicate(game.settings.get("foundryvtt-reve-de-dragon", "calendrier")); this.calendrier = duplicate(game.settings.get("foundryvtt-reve-de-dragon", "calendrier"));
console.log("CALENDRIER", this.calendrier); //console.log("CALENDRIER", this.calendrier);
if (this.calendrier == undefined || this.calendrier.moisRdD == undefined) { if (this.calendrier == undefined || this.calendrier.moisRdD == undefined) {
this.calendrier = {};
this.calendrier.heureRdD = 0; // Index dans heuresList this.calendrier.heureRdD = 0; // Index dans heuresList
this.calendrier.minutesRelative = 0; this.calendrier.minutesRelative = 0;
this.calendrier.moisRdD = 0; // Index dans heuresList this.calendrier.moisRdD = 0; // Index dans heuresList
@ -52,6 +55,7 @@ export class RdDCalendrier extends Application {
// position // position
this.calendrierPos = duplicate(game.settings.get("foundryvtt-reve-de-dragon", "calendrier-pos")); this.calendrierPos = duplicate(game.settings.get("foundryvtt-reve-de-dragon", "calendrier-pos"));
if (this.calendrierPos == undefined || this.calendrierPos.top == undefined) { if (this.calendrierPos == undefined || this.calendrierPos.top == undefined) {
this.calendrierPos = {};
this.calendrierPos.top = 200; this.calendrierPos.top = 200;
this.calendrierPos.left = 200; this.calendrierPos.left = 200;
if (game.user.isGM) { // Uniquement si GM if (game.user.isGM) { // Uniquement si GM
@ -88,6 +92,14 @@ export class RdDCalendrier extends Application {
return day + " " + heuresList[month]; return day + " " + heuresList[month];
} }
/* -------------------------------------------- */
getNumericDateFromIndex(index = undefined) {
if (!index) index = this.getCurrentDayIndex();
let month = Math.floor(index / 28)
return { month: heuresList[month],
day: (index - (month * 28)) + 1 }
}
/* -------------------------------------------- */ /* -------------------------------------------- */
getCurrentHeure() { getCurrentHeure() {
return heuresList[this.calendrier.heureRdD]; return heuresList[this.calendrier.heureRdD];
@ -98,6 +110,10 @@ export class RdDCalendrier extends Application {
return (this.calendrier.moisRdD * 28) + this.calendrier.jour; return (this.calendrier.moisRdD * 28) + this.calendrier.jour;
} }
/* -------------------------------------------- */
getIndexFromDate(jour, mois) {
return (heuresDef[mois].heure * 28) + (jour-1);
}
/* -------------------------------------------- */ /* -------------------------------------------- */
getJoursSuivants(num) { getJoursSuivants(num) {
let jours = []; let jours = [];
@ -110,9 +126,9 @@ export class RdDCalendrier extends Application {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
ajouterNombreAstral(index) { async ajouterNombreAstral(index) {
return { return {
nombreAstral: new Roll("1d12").roll().total, nombreAstral: await RdDDice.rollTotal("1dh"),
valeursFausses: [], valeursFausses: [],
index: index index: index
} }
@ -124,6 +140,12 @@ export class RdDCalendrier extends Application {
return this.getNombreAstral(indexDate); return this.getNombreAstral(indexDate);
} }
/* -------------------------------------------- */
resetNombreAstral( ) {
this.listeNombreAstral = [];
game.settings.set("foundryvtt-reve-de-dragon", "liste-nombre-astral", this.listeNombreAstral);
}
/* -------------------------------------------- */ /* -------------------------------------------- */
getNombreAstral(indexDate) { getNombreAstral(indexDate) {
const liste = this.listeNombreAstral ?? this._loadListNombreAstral(); const liste = this.listeNombreAstral ?? this._loadListNombreAstral();
@ -199,7 +221,7 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */ /* -------------------------------------------- */
syncPlayerTime(calendrier) { syncPlayerTime(calendrier) {
this.calendrier = duplicate(calendrier); // Local copy update this.calendrier = duplicate(calendrier); // Local copy update
this.updateDisplay(); // Then update this.updateDisplay();
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -247,24 +269,21 @@ export class RdDCalendrier extends Application {
console.log(request); console.log(request);
let jourDiff = this.getLectureAstrologieDifficulte(request.date); let jourDiff = this.getLectureAstrologieDifficulte(request.date);
let niveau = Number(request.astrologie.data.niveau) + Number(request.conditions) + Number(jourDiff) + Number(request.etat); let niveau = Number(request.astrologie.data.niveau) + Number(request.conditions) + Number(jourDiff) + Number(request.etat);
let rolled = await RdDResolutionTable.rollData({ let rollData= {
caracValue: request.carac_vue, caracValue: request.carac_vue,
finalLevel: niveau, finalLevel: niveau,
showDice: false showDice: false
}); };
await RdDResolutionTable.rollData(rollData);
let nbAstral = this.getNombreAstral(request.date); let nbAstral = this.getNombreAstral(request.date);
let nbAstralFaux = nbAstral; request.rolled = rollData.rolled;
request.isValid = true; request.isValid = true;
request.rolled = rolled; if (!request.rolled.isSuccess) {
if (!rolled.isSuccess) {
request.isValid = false; request.isValid = false;
while (nbAstralFaux == nbAstral) { nbAstral = await RdDDice.rollTotal("1dhr"+nbAstral);
nbAstralFaux = new Roll("1d12").roll().total;
}
nbAstral = nbAstralFaux;
// Mise à jour des nombres astraux du joueur // Mise à jour des nombres astraux du joueur
let astralData = this.listeNombreAstral.find((nombreAstral, i) => nombreAstral.index == request.date); let astralData = this.listeNombreAstral.find((nombreAstral, i) => nombreAstral.index == request.date);
astralData.valeursFausses.push({ actorId: request.id, nombreAstral: nbAstralFaux }); astralData.valeursFausses.push({ actorId: request.id, nombreAstral: nbAstral });
game.settings.set("foundryvtt-reve-de-dragon", "liste-nombre-astral", this.listeNombreAstral); game.settings.set("foundryvtt-reve-de-dragon", "liste-nombre-astral", this.listeNombreAstral);
} }
request.nbAstral = nbAstral; request.nbAstral = nbAstral;
@ -338,7 +357,7 @@ export class RdDCalendrier extends Application {
if (game.user.isGM) { if (game.user.isGM) {
dateHTML = dateHTML + " - NA: " + this.getCurrentNombreAstral(); dateHTML = dateHTML + " - NA: " + this.getCurrentNombreAstral();
} }
for (let handle of document.getElementsByClassName("calendar-move-handle")) { for (let handle of document.getElementsByClassName("calendar-date-rdd")) {
handle.innerHTML = dateHTML; handle.innerHTML = dateHTML;
} }
for (let heure of document.getElementsByClassName("calendar-heure-texte")) { for (let heure of document.getElementsByClassName("calendar-heure-texte")) {

View File

@ -1,4 +1,5 @@
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
const tableCaracDerivee = { const tableCaracDerivee = {
// xp: coût pour passer du niveau inférieur à ce niveau // xp: coût pour passer du niveau inférieur à ce niveau
@ -61,7 +62,7 @@ export class RdDCarac {
static computeTotal(carac, beaute = undefined) { static computeTotal(carac, beaute = undefined) {
const total = Object.values(carac).filter(c => !c.derivee) const total = Object.values(carac).filter(c => !c.derivee)
.map(it => parseInt(it.value)) .map(it => parseInt(it.value))
.reduce((a, b) => a + b, 0); .reduce(Misc.sum(), 0);
const beauteSuperieur10 = Math.max((beaute ?? 10) - 10, 0); const beauteSuperieur10 = Math.max((beaute ?? 10) - 10, 0);
return total + beauteSuperieur10; return total + beauteSuperieur10;
} }
@ -94,7 +95,7 @@ export class RdDCarac {
* ainsi que de Perception active et volontaire. * ainsi que de Perception active et volontaire.
*/ */
static isActionPhysique(selectedCarac) { static isActionPhysique(selectedCarac) {
return Grammar.toLowerCaseNoAccent(selectedCarac?.label).match(/(apparence|force|agilite|dexterite|vue|ouie|odorat|empathie|melee|tir|lancer|derobee)/); return Grammar.toLowerCaseNoAccent(selectedCarac?.label)?.match(/(apparence|force|agilite|dexterite|vue|ouie|odorat|empathie|melee|tir|lancer|derobee)/);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -75,36 +75,36 @@ export class RdDCombatManager extends Combat {
const currentId = this.combatant._id; const currentId = this.combatant._id;
// calculate initiative // calculate initiative
for (let cId = 0; cId < ids.length; cId++) { for (let cId = 0; cId < ids.length; cId++) {
const c = this.getCombatant(ids[cId]); const combatant = this.getCombatant(ids[cId]);
//if (!c) return results; //if (!c) return results;
let rollFormula = formula; // Init per default let rollFormula = formula; // Init per default
if (!rollFormula) { if (!rollFormula) {
let armeCombat, competence; let armeCombat, competence;
if (c.actor.data.type == 'creature' || c.actor.data.type == 'entite') { if (combatant.actor.data.type == 'creature' || combatant.actor.data.type == 'entite') {
for (const competenceItemData of c.actor.data.items) { for (const competenceItemData of combatant.actor.data.items) {
if (competenceItemData.data.iscombat) { if (competenceItemData.data.iscombat) {
competence = duplicate(competenceItemData); competence = duplicate(competenceItemData);
} }
} }
rollFormula = "2+( (" + RdDCombatManager.calculInitiative(competence.data.niveau, competence.data.carac_value) + ")/100)"; rollFormula = "2+( (" + RdDCombatManager.calculInitiative(competence.data.niveau, competence.data.carac_value) + ")/100)";
} else { } else {
for (const itemData of c.actor.data.items) { for (const itemData of combatant.actor.data.items) {
if (itemData.type == "arme" && itemData.data.equipe) { if (itemData.type == "arme" && itemData.data.equipe) {
armeCombat = duplicate(itemData); armeCombat = duplicate(itemData);
} }
} }
let compName = (armeCombat == undefined) ? "Corps à corps" : armeCombat.data.competence; let compName = (armeCombat == undefined) ? "Corps à corps" : armeCombat.data.competence;
competence = RdDItemCompetence.findCompetence(c.actor.data.items, compName); competence = RdDItemCompetence.findCompetence(combatant.actor.data.items, compName);
let bonusEcaille = (armeCombat && armeCombat.data.magique) ? armeCombat.data.ecaille_efficacite : 0; let bonusEcaille = (armeCombat && armeCombat.data.magique) ? armeCombat.data.ecaille_efficacite : 0;
rollFormula = "2+( (" + RdDCombatManager.calculInitiative(competence.data.niveau, Misc.data(c.actor).data.carac[competence.data.defaut_carac].value, bonusEcaille) + ")/100)"; rollFormula = "2+( (" + RdDCombatManager.calculInitiative(competence.data.niveau, Misc.data(combatant.actor).data.carac[competence.data.defaut_carac].value, bonusEcaille) + ")/100)";
} }
} }
//console.log("Combatat", c); //console.log("Combatat", c);
const roll = super._getInitiativeRoll(c, rollFormula); const roll = combatant.getInitiativeRoll(rollFormula);
if (roll.total <= 0) roll.total = 0.00; if (roll.total <= 0) roll.total = 0.00;
console.log("Compute init for", rollFormula, roll.total); console.log("Compute init for", rollFormula, roll.total);
await this.updateEmbeddedEntity("Combatant", { _id: c._id, initiative: roll.total }); await this.updateEmbeddedDocuments("Combatant", [{ _id: combatant._id, initiative: roll.total }]);
// Send a chat message // Send a chat message
let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode"); let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode");
@ -112,12 +112,12 @@ export class RdDCombatManager extends Combat {
{ {
speaker: { speaker: {
scene: canvas.scene._id, scene: canvas.scene._id,
actor: c.actor ? c.actor._id : null, actor: combatant.actor ? combatant.actor._id : null,
token: c.token._id, token: combatant.token._id,
alias: c.token.name, alias: combatant.token.name,
sound: CONFIG.sounds.dice, sound: CONFIG.sounds.dice,
}, },
flavor: `${c.token.name} a fait son jet d'Initiative (${messageOptions.initInfo}) flavor: `${combatant.token.name} a fait son jet d'Initiative (${messageOptions.initInfo})
<br> <br>
`, `,
}, },
@ -143,35 +143,31 @@ export class RdDCombatManager extends Combat {
// Gestion des armes 1/2 mains // Gestion des armes 1/2 mains
let armesEquipe = []; let armesEquipe = [];
for (const arme of armes) { for (const arme of armes) {
if (arme.data.equipe) { let armeData = Misc.data(arme);
armesEquipe.push(arme); if (armeData.data.equipe) {
let comp = competences.find(c => c.name == arme.data.competence); let compData = competences.map(c => Misc.data(c)).find(c => c.name == armeData.data.competence);
arme.data.initiative = RdDCombatManager.calculInitiative(arme.data.niveau, carac[comp.data.defaut_carac].value);
armesEquipe.push(armeData);
armeData.data.initiative = RdDCombatManager.calculInitiative(armeData.data.niveau, carac[compData.data.defaut_carac].value);
// Dupliquer les armes pouvant être à 1 main et 2 mains en patchant la compétence // Dupliquer les armes pouvant être à 1 main et 2 mains en patchant la compétence
if (arme.data.unemain && !arme.data.deuxmains) { if (armeData.data.unemain && !armeData.data.deuxmains) {
arme.data.mainInfo = "(1m)"; armeData.data.mainInfo = "(1m)";
} else if (!arme.data.unemain && arme.data.deuxmains) { } else if (!armeData.data.unemain && armeData.data.deuxmains) {
arme.data.mainInfo = "(2m)"; armeData.data.mainInfo = "(2m)";
} else if (arme.data.unemain && arme.data.deuxmains) { } else if (armeData.data.unemain && armeData.data.deuxmains) {
arme.data.mainInfo = "(1m)"; armeData.data.mainInfo = "(1m)";
let arme2main = duplicate(arme); let arme2main = duplicate(armeData);
arme2main.data.mainInfo = "(2m)"; arme2main.data.mainInfo = "(2m)";
arme2main.data.dommages = arme2main.data.dommages.split("/")[1]; // Existence temporaire uniquement dans la liste des armes, donc OK arme2main.data.dommages = arme2main.data.dommages.split("/")[1]; // Existence temporaire uniquement dans la liste des armes, donc OK
arme2main.data.competence = arme2main.data.competence.replace(" 1 main", " 2 mains"); // Replace ! arme2main.data.competence = arme2main.data.competence.replace(" 1 main", " 2 mains"); // Replace !
let comp = competences.find(c => c.name == arme2main.data.competence); let comp = Misc.data(competences.find(c => c.name == arme2main.data.competence));
arme2main.data.niveau = comp.data.niveau; arme2main.data.niveau = comp.data.niveau;
arme2main.data.initiative = RdDCombatManager.calculInitiative(arme2main.data.niveau, carac[comp.data.defaut_carac].value); arme2main.data.initiative = RdDCombatManager.calculInitiative(arme2main.data.niveau, carac[comp.data.defaut_carac].value);
armesEquipe.push(arme2main); armesEquipe.push(arme2main);
} }
} }
} }
return armesEquipe.sort((a, b) => { return armesEquipe.sort(Misc.ascending(armeData => armeData.name + (armeData.data.mainInfo ?? '')));
const nameA = a.name + (a.data.mainInfo ?? '');
const nameB = b.name + (b.data.mainInfo ?? '');
if (nameA > nameB) return 1;
if (nameA < nameB) return -1;
return 0;
});
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -180,6 +176,7 @@ export class RdDCombatManager extends Combat {
ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`) ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`)
return []; return [];
} }
const actorData = Misc.data(combatant.actor);
let items = combatant.actor.data.items; let items = combatant.actor.data.items;
let actions = [] let actions = []
if (combatant.actor.isCreature()) { if (combatant.actor.isCreature()) {
@ -188,13 +185,14 @@ export class RdDCombatManager extends Combat {
} else { } else {
// Recupération des items 'arme' // Recupération des items 'arme'
let armes = items.filter(it => RdDItemArme.isArmeUtilisable(it)) let armes = items.filter(it => RdDItemArme.isArmeUtilisable(it))
.map(arme => duplicate(arme)) /* pas de changements aux armes d'origine */
.concat(RdDItemArme.mainsNues()); .concat(RdDItemArme.mainsNues());
let competences = items.filter(it => it.type == 'competence'); let competences = items.filter(it => it.type == 'competence');
actions = actions.concat(RdDCombatManager.finalizeArmeList(armes, competences, Misc.data(combatant.actor).data.carac)); actions = actions.concat(RdDCombatManager.finalizeArmeList(armes, competences, actorData.data.carac));
actions.push({ name: "Draconic", data: { initOnly: true, competence: "Draconic" } }); if (actorData.data.attributs.hautrevant.value){
actions.push({ name: "Draconic", data: { initOnly: true, competence: "Draconic" } });
}
} }
actions.push({ name: "Autre action", data: { initOnly: true, competence: "Autre action" } }); actions.push({ name: "Autre action", data: { initOnly: true, competence: "Autre action" } });
@ -268,7 +266,7 @@ export class RdDCombatManager extends Combat {
let initOffset = 0; let initOffset = 0;
let caracForInit = 0; let caracForInit = 0;
let compNiveau = 0; let compNiveau = 0;
let competence = { name: "Aucune" }; let compData = { name: "Aucune" };
if (combatant.actor.getSurprise() == "totale") { if (combatant.actor.getSurprise() == "totale") {
initOffset = -1; // To force 0 initOffset = -1; // To force 0
initInfo = "Surprise Totale" initInfo = "Surprise Totale"
@ -283,24 +281,24 @@ export class RdDCombatManager extends Combat {
initInfo = "Draconic" initInfo = "Draconic"
} else { } else {
initOffset = 3; // Melée = 3.XX initOffset = 3; // Melée = 3.XX
competence = RdDItemCompetence.findCompetence(combatant.actor.data.items, arme.data.competence); compData = Misc.data(RdDItemCompetence.findCompetence(combatant.actor.data.items, arme.data.competence));
compNiveau = competence.data.niveau; compNiveau = compData.data.niveau;
initInfo = arme.name + " / " + arme.data.competence; initInfo = arme.name + " / " + arme.data.competence;
if (combatant.actor.data.type == 'creature' || combatant.actor.data.type == 'entite') { if (combatant.actor.data.type == 'creature' || combatant.actor.data.type == 'entite') {
caracForInit = competence.data.carac_value; caracForInit = compData.data.carac_value;
if (competence.data.categorie == "lancer") { if (compData.data.categorie == "lancer") {
initOffset = 5; initOffset = 5;
} }
} else { } else {
caracForInit = Misc.data(combatant.actor).data.carac[competence.data.defaut_carac].value; caracForInit = Misc.data(combatant.actor).data.carac[compData.data.defaut_carac].value;
if (competence.data.categorie == "lancer") { // Offset de principe pour les armes de jet if (compData.data.categorie == "lancer") { // Offset de principe pour les armes de jet
initOffset = 4; initOffset = 4;
} }
if (competence.data.categorie == "tir") { // Offset de principe pour les armes de jet if (compData.data.categorie == "tir") { // Offset de principe pour les armes de jet
initOffset = 5; initOffset = 5;
} }
if (competence.data.categorie == "melee") { // Offset de principe pour les armes de jet if (compData.data.categorie == "melee") { // Offset de principe pour les armes de jet
initOffset = 3; initOffset = 3;
} }
} }
@ -340,8 +338,8 @@ export class RdDCombat {
static init() { static init() {
this.initStorePasseArmes(); this.initStorePasseArmes();
Hooks.on("updateCombat", (combat, data) => { RdDCombat.onUpdateCombat(combat, data) }); Hooks.on("updateCombat", (combat, change, options, userId) => { RdDCombat.onUpdateCombat(combat, change, options, userId) });
Hooks.on("preDeleteCombat", (combat, options) => { RdDCombat.onPreDeleteCombat(combat, options); }); Hooks.on("preDeleteCombat", (combat, options, userId) => { RdDCombat.onPreDeleteCombat(combat, options, userId); });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -363,14 +361,14 @@ export class RdDCombat {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static onUpdateCombat(combat, data) { static onUpdateCombat(combat, change, options, userId) {
if (combat.data.round != 0 && combat.turns && combat.data.active) { if (combat.data.round != 0 && combat.turns && combat.data.active) {
RdDCombat.combatNouveauTour(combat); RdDCombat.combatNouveauTour(combat);
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static onPreDeleteCombat(combat, options) { static onPreDeleteCombat(combat, options, userId) {
if (game.user.isGM) { if (game.user.isGM) {
combat.cleanItemUse(); combat.cleanItemUse();
ChatUtility.removeChatMessageContaining(`<div data-combatid="${combat.id}" data-combatmessage="actor-turn-summary">`) ChatUtility.removeChatMessageContaining(`<div data-combatid="${combat.id}" data-combatmessage="actor-turn-summary">`)
@ -663,7 +661,7 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
static isEchecTotal(rollData) { static isEchecTotal(rollData) {
if (!rollData.attackerRoll && rollData.ajustements.surprise.used) { if (!rollData.attackerRoll && rollData.ajustements.surprise.used) {
return rollData.rolled.isEchec; return rollData.rolled.isEchec && rollData.rolled.code != 'notSign';
} }
return rollData.rolled.isETotal; return rollData.rolled.isETotal;
} }
@ -728,7 +726,6 @@ export class RdDCombat {
surpriseDefenseur: this.defender.getSurprise(true), surpriseDefenseur: this.defender.getSurprise(true),
essais: {} essais: {}
}; };
rollData.diviseurSignificative = this._getDiviseurSignificative(rollData);
if (this.attacker.isCreature()) { if (this.attacker.isCreature()) {
RdDItemCompetenceCreature.setRollDataCreature(rollData); RdDItemCompetenceCreature.setRollDataCreature(rollData);
@ -799,21 +796,19 @@ export class RdDCombat {
} }
// # utilisation esquive // # utilisation esquive
let esquiveUsage = 0; const esquive = Misc.data(this.defender.getCompetence("esquive"));
let esquive = this.defender.getCompetence("esquive"); const corpsACorps = Misc.data(this.defender.getCompetence("Corps à corps"));
if (esquive) { const esquiveUsage = esquive ? this.defender.getItemUse(esquive._id) : 0;
esquiveUsage = this.defender.getItemUse(esquive._id);
}
const paramChatDefense = { const paramChatDefense = {
passeArme: attackerRoll.passeArme, passeArme: attackerRoll.passeArme,
essais: attackerRoll.essais, essais: attackerRoll.essais,
defender: this.defender, defender: Misc.data(this.defender),
attacker: this.attacker, attacker: Misc.data(this.attacker),
attackerId: this.attackerId, attackerId: this.attackerId,
esquiveUsage: esquiveUsage, esquiveUsage: esquiveUsage,
defenderTokenId: this.defenderTokenId, defenderTokenId: this.defenderTokenId,
mainsNues: attackerRoll.dmg.mortalite != 'mortel' && this.defender.getCompetence("Corps à corps"), mainsNues: attackerRoll.dmg.mortalite != 'mortel' && corpsACorps,
armes: this._filterArmesParade(this.defender, attackerRoll.competence, attackerRoll.arme), armes: this._filterArmesParade(this.defender, attackerRoll.competence, attackerRoll.arme),
diffLibre: attackerRoll.ajustements?.diffLibre?.value ?? 0, diffLibre: attackerRoll.ajustements?.diffLibre?.value ?? 0,
attaqueParticuliere: attackerRoll.particuliere, attaqueParticuliere: attackerRoll.particuliere,
@ -851,7 +846,7 @@ export class RdDCombat {
attackerId: this.attacker?.data._id, attackerId: this.attacker?.data._id,
defenderId: this.defender?.data._id, defenderId: this.defender?.data._id,
defenderTokenId: this.defenderTokenId, defenderTokenId: this.defenderTokenId,
defenderRoll: duplicate(defenderRoll), defenderRoll: defenderRoll,
paramChatDefense: paramChatDefense, paramChatDefense: paramChatDefense,
rollMode: true rollMode: true
} }
@ -887,7 +882,7 @@ export class RdDCombat {
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name), whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.html', { content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.html', {
attackerId: this.attackerId, attackerId: this.attackerId,
attacker: this.attacker, attacker: Misc.data(this.attacker),
defenderTokenId: this.defenderTokenId, defenderTokenId: this.defenderTokenId,
essais: attackerRoll.essais essais: attackerRoll.essais
}) })
@ -958,20 +953,20 @@ export class RdDCombat {
_prepareParade(attackerRoll, armeParade) { _prepareParade(attackerRoll, armeParade) {
const compName = armeParade.data.competence; const compName = armeParade.data.competence;
const armeAttaque = attackerRoll.arme; const armeAttaque = attackerRoll.arme;
const parade = Misc.data(this.defender.getCompetence(compName));
let defenderRoll = { let defenderRoll = {
passeArme: attackerRoll.passeArme, passeArme: attackerRoll.passeArme,
diffLibre: attackerRoll.diffLibre, diffLibre: attackerRoll.diffLibre,
attackerRoll: attackerRoll, attackerRoll: attackerRoll,
competence: this.defender.getCompetence(compName), competence: parade,
arme: armeParade, arme: armeParade,
surprise: this.defender.getSurprise(true), surprise: this.defender.getSurprise(true),
needParadeSignificative: ReglesOptionelles.isUsing('categorieParade') && RdDItemArme.needParadeSignificative(armeAttaque, armeParade), needParadeSignificative: ReglesOptionelles.isUsing('categorieParade') && RdDItemArme.needParadeSignificative(armeAttaque, armeParade),
needResist: RdDItemArme.needArmeResist(armeAttaque, armeParade), needResist: RdDItemArme.needArmeResist(armeAttaque, armeParade),
carac: this.defender.data.data.carac, carac: Misc.templateData(this.defender).carac,
show: {} show: {}
}; };
defenderRoll.diviseurSignificative = this._getDiviseurSignificative(defenderRoll);
if (this.defender.isCreature()) { if (this.defender.isCreature()) {
RdDItemCompetenceCreature.setRollDataCreature(defenderRoll); RdDItemCompetenceCreature.setRollDataCreature(defenderRoll);
@ -980,24 +975,6 @@ export class RdDCombat {
return defenderRoll; return defenderRoll;
} }
/* -------------------------------------------- */
_getDiviseurSignificative(defenderRoll) {
let facteurSign = 1;
if (defenderRoll.surprise == 'demi') {
facteurSign *= 2;
}
if (defenderRoll.needParadeSignificative) {
facteurSign *= 2;
}
if (RdDBonus.isDefenseAttaqueFinesse(defenderRoll)) {
facteurSign *= 2;
}
if (!ReglesOptionelles.isUsing('tripleSignificative')) {
facteurSign = Math.min(facteurSign, 4);
}
return facteurSign;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
_onParadeParticuliere(defenderRoll) { _onParadeParticuliere(defenderRoll) {
console.log("RdDCombat._onParadeParticuliere >>>", defenderRoll); console.log("RdDCombat._onParadeParticuliere >>>", defenderRoll);
@ -1033,7 +1010,7 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
async esquive(attackerRoll) { async esquive(attackerRoll) {
let esquive = this.defender.getCompetence("esquive"); const esquive = Misc.data(this.defender.getCompetence("esquive"));
if (esquive == undefined) { if (esquive == undefined) {
ui.notifications.error(this.defender.name + " n'a pas de compétence 'esquive'"); ui.notifications.error(this.defender.name + " n'a pas de compétence 'esquive'");
return; return;
@ -1067,10 +1044,9 @@ export class RdDCombat {
competence: competence, competence: competence,
surprise: this.defender.getSurprise(true), surprise: this.defender.getSurprise(true),
surpriseDefenseur: this.defender.getSurprise(true), surpriseDefenseur: this.defender.getSurprise(true),
carac: this.defender.data.data.carac, carac: Misc.templateData(this.defender).carac,
show: {} show: {}
}; };
rollData.diviseurSignificative = this._getDiviseurSignificative(rollData);
if (this.defender.isCreature()) { if (this.defender.isCreature()) {
RdDItemCompetenceCreature.setRollDataCreature(rollData); RdDItemCompetenceCreature.setRollDataCreature(rollData);
@ -1136,7 +1112,7 @@ export class RdDCombat {
resistance -= perteResistance; resistance -= perteResistance;
defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise' : 'perte'; defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise' : 'perte';
defenderRoll.show.perteResistance = perteResistance; defenderRoll.show.perteResistance = perteResistance;
this.defender.updateEmbeddedEntity("OwnedItem", { _id: defenderRoll.arme._id, 'data.resistance': resistance }); this.defender.updateEmbeddedDocuments('Item', [{ _id: defenderRoll.arme._id, 'data.resistance': resistance }]);
} }
} }
} else { } else {
@ -1153,7 +1129,7 @@ export class RdDCombat {
resistance -= dmg; resistance -= dmg;
defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise' : 'perte'; defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise' : 'perte';
defenderRoll.show.perteResistance = dmg; defenderRoll.show.perteResistance = dmg;
this.defender.updateEmbeddedEntity("OwnedItem", { _id: defenderRoll.arme._id, 'data.resistance': resistance }); this.defender.updateEmbeddedDocuments('Item', [{ _id: defenderRoll.arme._id, 'data.resistance': resistance }]);
} }
} }
// Si l'arme de parade n'est pas un bouclier, jet de désarmement (p.132) // Si l'arme de parade n'est pas un bouclier, jet de désarmement (p.132)
@ -1203,7 +1179,7 @@ export class RdDCombat {
_computeImpactRecul(attaque) { _computeImpactRecul(attaque) {
const taille = this.defender.getTaille(); const taille = this.defender.getTaille();
const force = this.attacker.getForce(); const force = this.attacker.getForce();
const dommages = attaque.arme.data.dommagesReels; const dommages = attaque.arme.data.dommagesReels ?? attaque.arme.data.dommages;
return taille - (force + dommages); return taille - (force + dommages);
} }
@ -1234,7 +1210,7 @@ export class RdDCombat {
attackerId: this.attackerId, attackerId: this.attackerId,
defenderTokenId: defenderTokenId, defenderTokenId: defenderTokenId,
attackerRoll: attackerRoll, attackerRoll: attackerRoll,
gmId: game.users.entities.find(u => u.isGM)?.id, gmId: Misc.connectedGMOrUser(),
} }
}); });
} }
@ -1252,7 +1228,7 @@ export class RdDCombat {
return true; return true;
} }
let rolled = await RdDResolutionTable.roll(this.attacker.getReveActuel(), - Number(this.defender.data.data.carac.niveau.value)); let rolled = await RdDResolutionTable.roll(this.attacker.getReveActuel(), - Number(Misc.templateData(this.defender).carac.niveau.value));
let message = { let message = {
content: "Jet de points actuels de rêve à " + rolled.finalLevel + RdDResolutionTable.explain(rolled) + "<br>", content: "Jet de points actuels de rêve à " + rolled.finalLevel + RdDResolutionTable.explain(rolled) + "<br>",

View File

@ -1,6 +1,6 @@
/* -------------------------------------------- */ /* -------------------------------------------- */
import { DeDraconique } from "./de-draconique.js"; import { DialogCreateSigneDraconique } from "./dialog-create-signedraconique.js";
import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemCompetence } from "./item-competence.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDCarac } from "./rdd-carac.js"; import { RdDCarac } from "./rdd-carac.js";
@ -11,9 +11,9 @@ import { RdDRollResolutionTable } from "./rdd-roll-resolution-table.js";
import { RdDRollTables } from "./rdd-rolltables.js"; import { RdDRollTables } from "./rdd-rolltables.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { TMRRencontres } from "./tmr-rencontres.js"; import { TMRRencontres } from "./tmr-rencontres.js";
import { TMRType, TMRUtility } from "./tmr-utility.js"; import { TMRUtility } from "./tmr-utility.js";
const rddRollNumeric = /(\d+)\s*([\+\-]?\d+)?\s*(s)?/; const rddRollNumeric = /$(\d+)\s*([\+\-]?\d+)?\s*(s)?/;
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDCommands { export class RdDCommands {
@ -64,9 +64,11 @@ export class RdDCommands {
descr: `Effectue un jet de dés dans la table de résolution. Exemples: descr: `Effectue un jet de dés dans la table de résolution. Exemples:
<br><strong>/rdd</strong> ouvre la table de résolution <br><strong>/rdd</strong> ouvre la table de résolution
<br><strong>/rdd 10 3</strong> effectue un jet 10 à +3 <br><strong>/rdd 10 3</strong> effectue un jet 10 à +3
<br><strong>/rdd 10 +2</strong> effectue un jet 10 à +2
<br><strong>/rdd 15 -2</strong> effectue un jet 15 à -2 <br><strong>/rdd 15 -2</strong> effectue un jet 15 à -2
<br><strong>/rdd 15 0 s</strong> effectue un jet 15 à 0, avec significative requise` <br><strong>/rdd 15 0 s</strong> effectue un jet 15 à 0, avec significative requise
<br><strong>/rdd Vue Vigilance -2</strong> effectue un jet de Vue/Vigilance à -2 pour les tokens sélectionnés
<br><strong>/rdd vol déser +2</strong> effectue un jet de Volonté/Survie en désert à +2 pour les tokens sélectionnés
`
}); });
rddCommands.registerCommand({ path: ["/ddr"], func: (content, msg, params) => rddCommands.rollDeDraconique(msg), descr: "Lance un Dé Draconique" }); rddCommands.registerCommand({ path: ["/ddr"], func: (content, msg, params) => rddCommands.rollDeDraconique(msg), descr: "Lance un Dé Draconique" });
@ -81,6 +83,17 @@ export class RdDCommands {
descr: `Affiche les heures de chance et de malchance selon l'heure de naissance donnée en argument. Exemples: descr: `Affiche les heures de chance et de malchance selon l'heure de naissance donnée en argument. Exemples:
<br><strong>/astro Lyre</strong>` <br><strong>/astro Lyre</strong>`
}); });
rddCommands.registerCommand({
path: ["/signe", "+"], func: (content, msg, params) => rddCommands.creerSignesDraconiques(),
descr: "Crée un signe draconique et l'ajoute aux haut-rêvants choisis."
});
rddCommands.registerCommand({
path: ["/signe", "-"], func: (content, msg, params) => rddCommands.supprimerSignesDraconiquesEphemeres(),
descr: "Supprime les signes draconiques éphémères"
});
game.system.rdd.commands = rddCommands; game.system.rdd.commands = rddCommands;
} }
} }
@ -164,16 +177,30 @@ export class RdDCommands {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
help(msg, table = undefined) { async help(msg) {
this.help(msg, undefined);
}
async help(msg, table) {
let list = [] let list = []
this._buildSubTableHelp(list, table || this.commandsTable); this._buildSubTableHelp(list, table || this.commandsTable);
const messageAide = list.reduce((a, b) => a + '</li><li class="list-item">' + b);
RdDCommands._chatAnswer(msg, `Commandes disponibles<ul class="alterne-list"><li class="list-item">${messageAide}</li></ul>`); let html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/settings/dialog-aide-commands.html", { commands: list });
let d = new Dialog(
{
title: "Commandes disponibles dans le tchat",
content: html,
buttons: {},
},
{
width: 600, height: 500,
});
d.render(true);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static _chatAnswer(msg, content) { static _chatAnswer(msg, content) {
msg.whisper = [game.user._id]; msg.whisper = [game.user.id];
msg.content = content; msg.content = content;
ChatMessage.create(msg); ChatMessage.create(msg);
} }
@ -217,6 +244,27 @@ export class RdDCommands {
await this.rollRdDNumeric(msg, carac, diff, significative); await this.rollRdDNumeric(msg, carac, diff, significative);
return; return;
} }
let actors = canvas.tokens.controlled.map(it => it.actor).filter(it => it);
if (actors && actors.length > 0) {
let length = params.length;
let diff = Number(params[length - 1]);
if (Number.isInteger(Number(diff))) {
length--;
}
else {
diff = 0;
}
const caracName = params[0];
const compName = length > 1 ? params.slice(1, length).reduce((a, b) => `${a} ${b}`) : undefined;
for (let actor of actors) {
await actor.rollCaracCompetence(caracName, compName, diff);
}
return;
}
else {
ui.notifications.warn("Sélectionnez au moins un personnage pour lancer les dés")
}
} }
} }
@ -235,16 +283,14 @@ export class RdDCommands {
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollDeDraconique(msg) { async rollDeDraconique(msg) {
let ddr = new DeDraconique().evaluate(); let ddr = await RdDDice.rollTotal("1dr + 7", { showDice:true });
ddr.showDice = true; RdDCommands._chatAnswer(msg, `Lancer d'un Dé draconique: ${ddr}`);
await RdDDice.showDiceSoNice(ddr);
RdDCommands._chatAnswer(msg, `Lancer d'un Dé draconique: ${ddr.total}`);
} }
getTMRAleatoire(msg, params) { async getTMRAleatoire(msg, params) {
if (params.length < 2) { if (params.length < 2) {
let type = params[0]; let type = params[0];
const tmr = TMRUtility.getTMRAleatoire(type ? (it => it.type == type) : (it => true)); const tmr = await TMRUtility.getTMRAleatoire(type ? (it => it.type == type) : (it => true));
RdDCommands._chatAnswer(msg, `Case aléatoire: ${tmr.coord} - ${tmr.label}`); RdDCommands._chatAnswer(msg, `Case aléatoire: ${tmr.coord} - ${tmr.label}`);
} }
else { else {
@ -276,5 +322,20 @@ export class RdDCommands {
} }
} }
async creerSignesDraconiques() {
DialogCreateSigneDraconique.createSigneForActors();
return true;
}
async supprimerSignesDraconiquesEphemeres() {
game.actors.forEach(actor => {
const ephemeres = actor.filterItems(item => Misc.data(item).type = 'signedraconique' && Misc.data(item).data.ephemere)
.map(item => item.id);
if (ephemeres.length > 0) {
actor.deleteEmbeddedDocuments("Item", ephemeres);
}
});
return true;
}
} }

View File

@ -14,7 +14,7 @@ const typeDisplayName = {
"ombre": "Ombre de Thanatos", "ombre": "Ombre de Thanatos",
"souffle": "Souffle de Dragon", "souffle": "Souffle de Dragon",
"tete": "Tête de Dragon", "tete": "Tête de Dragon",
"ingredient": "Ingrédient", "nourritureboisson": "Nourriture & boisson",
"rencontresTMR": "Rencontre des TMR", "rencontresTMR": "Rencontre des TMR",
"competencecreature": "Compétence de créature", "competencecreature": "Compétence de créature",
"nombreastral": "Nombre astral", "nombreastral": "Nombre astral",
@ -36,14 +36,14 @@ export class RddCompendiumOrganiser {
Hooks.on('renderCompendium', async (pack, html, data) => RddCompendiumOrganiser.onRenderCompendium(pack, html, data)) Hooks.on('renderCompendium', async (pack, html, data) => RddCompendiumOrganiser.onRenderCompendium(pack, html, data))
} }
static async onRenderCompendium(pack, html, data) { static async onRenderCompendium(compendium, html, data) {
console.log('onRenderCompendium', pack, html, data); console.log('onRenderCompendium', compendium, html, data);
let pack = compendium.collection
if (pack.metadata.system === 'foundryvtt-reve-de-dragon') { if (pack.metadata.system === 'foundryvtt-reve-de-dragon') {
const content = await pack.getContent(); const content = await pack.getContent();
html.find('.directory-item').each((i, element) => { html.find('.directory-item').each((i, element) => {
let entity = content.find(it => it._id === element.dataset.entryId); let entity = pack.get(element.dataset.documentId);
if (entity?.entity === 'Actor' || entity?.entity === 'Item') { if (entity?.entity === 'Actor' || entity?.entity === 'Item') {
const typeName = typeDisplayName[entity.data.type] ?? Misc.upperFirst(entity.data.type); const typeName = typeDisplayName[entity.data.type] ?? Misc.upperFirst(entity.data.type);
RddCompendiumOrganiser.insertEntityType(element, typeName); RddCompendiumOrganiser.insertEntityType(element, typeName);

View File

@ -1,15 +1,166 @@
import { ChatUtility } from "./chat-utility.js"; import { ChatUtility } from "./chat-utility.js";
import { SYSTEM_RDD } from "./constants.js";
import { Misc } from "./misc.js";
function img(src) {
return `<img src="${src}" class="dice-img" />`
}
function iconHeure(heure) {
if (heure < 10) {
heure = '0' + heure;
}
return `systems/foundryvtt-reve-de-dragon/icons/heures/hd${heure}.webp`
}
const imagesHeures = [1, 2, 3, 4, 5, 6, 7, 9, 9, 10, 11, 12].map(it => iconHeure(it));
const imgSigneDragon = img(imagesHeures[4]);
/** De7 pour les jets de rencontre */
export class De7 extends Die {
/** @override */
static DENOMINATION = "7";
static diceSoNiceData(system) {
return {
type: "d7",
font: "HeuresDraconiques",
fontScale: 0.7,
labels: ['1', '2', '3', '4', '5', '6', 'd', '0'],
system: system
}
}
constructor(termData) {
termData.faces = 8;
super(termData);
}
async evaluate() {
super.evaluate();
this.explode("x=8");
return this;
}
get total() {
return this.values.filter(it => it != 8).reduce(Misc.sum(), 0);
}
static getResultLabel(result) {
switch (result) {
case 7: return imgSigneDragon;
}
return result;
}
}
/** DeDraconique pour le D8 sans limite avec 8=>0 */
export class DeDraconique extends Die {
static DENOMINATION = "r";
static diceSoNiceData(system) {
return {
type: "dr",
font: "HeuresDraconiques",
fontScale: 0.7,
labels: ['1', '2', '3', '4', '5', '6', 'd', '0'],
system: system
}
}
constructor(termData) {
termData.faces = 8;
super(termData);
}
async evaluate() {
super.evaluate();
this.explode("x=7");
return this;
}
get total() {
return this.values.filter(it => it != 8).reduce(Misc.sum(), 0);
}
static getResultLabel(result) {
switch (result) {
case 7: return imgSigneDragon;
case 8: return 0;
}
return result;
}
}
/** De 12 avec les heures */
export class DeHeure extends Die {
/** @override */
static DENOMINATION = "h";
static diceSoNiceData(system) {
return {
type: "dh",
font: "HeuresDraconiques",
labels: ['v', 'i', 'f', 'o', 'd', 'e', 'l', 's', 'p', 'a', 'r', 'c'],
system: system
}
}
constructor(termData) {
termData.faces = 12;
super(termData);
}
static getResultLabel(result) {
return img(imagesHeures[result - 1]);
}
}
export class RdDDice { export class RdDDice {
static init() {
CONFIG.Dice.terms[De7.DENOMINATION] = De7;
CONFIG.Dice.terms[DeDraconique.DENOMINATION] = DeDraconique;
CONFIG.Dice.terms[DeHeure.DENOMINATION] = DeHeure;
}
static async roll(formula, options = { showDice: false }) {
const roll = new Roll(formula);
await roll.evaluate({ async: true });
if (options.showDice) {
roll.showDice = options.showDice;
}
await RdDDice.show(roll, game.settings.get("core", "rollMode"));
return roll;
}
static async rollTotal(formula) {
const roll = new Roll(formula);
await roll.evaluate({ async: true });
return roll.total;
}
static async rollOneOf(array) {
const roll = await RdDDice.rollTotal(`1d${array.length}`);
return array[roll-1];
}
static diceSoNiceReady(dice3d) {
for (const system of Object.keys(dice3d.DiceFactory.systems)) {
dice3d.addDicePreset(De7.diceSoNiceData(system));
dice3d.addDicePreset(DeDraconique.diceSoNiceData(system));
dice3d.addDicePreset(DeHeure.diceSoNiceData(system));
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static async show(roll, rollMode = undefined) { static async show(roll, rollMode = undefined) {
if (roll.showDice || game.settings.get("foundryvtt-reve-de-dragon", "dice-so-nice") == true) { if (roll.showDice || game.settings.get(SYSTEM_RDD, "dice-so-nice") == true) {
await this.showDiceSoNice(roll, rollMode); await this.showDiceSoNice(roll, rollMode);
} }
return roll; return roll;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async showDiceSoNice(roll, rollMode = undefined) { static async showDiceSoNice(roll, rollMode = undefined) {
if (game.modules.get("dice-so-nice") && game.modules.get("dice-so-nice").active) { if (game.modules.get("dice-so-nice") && game.modules.get("dice-so-nice").active) {
@ -26,7 +177,7 @@ export class RdDDice {
whisper = ChatUtility.getUsers(user => user.active); whisper = ChatUtility.getUsers(user => user.active);
break; break;
case "selfroll": case "selfroll":
whisper = [game.user._id]; whisper = [game.user.id];
break; break;
} }
await game.dice3d.showForRoll(roll, game.user, true, whisper, blind); await game.dice3d.showForRoll(roll, game.user, true, whisper, blind);

76
module/rdd-herbes.js Normal file
View File

@ -0,0 +1,76 @@
/* -------------------------------------------- */
import { RdDUtility } from "./rdd-utility.js";
import { Misc } from "./misc.js";
import { RdDCalendrier } from "./rdd-calendrier.js";
/* -------------------------------------------- */
export class RdDHerbes extends Item {
/* -------------------------------------------- */
static isHerbeSoin( botaniqueItem ) {
return Misc.templateData(botaniqueItem).categorie == 'Soin';
}
/* -------------------------------------------- */
static isHerbeRepos( botaniqueItem ) {
return Misc.templateData(botaniqueItem).categorie == 'Repos';
}
/* -------------------------------------------- */
static async initializeHerbes( ) {
this.herbesSoins = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.botanique', item => this.isHerbeSoin(item));
this.herbesRepos = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.botanique', item => this.isHerbeRepos(item));
}
/* -------------------------------------------- */
static buildHerbesList(listHerbes, max) {
let list = {}
for ( let herbe of listHerbes) {
let herbeData = Misc.templateData(herbe);
let brins = max - herbeData.niveau;
list[herbe.data.name] = `${herbe.data.name} (Bonus: ${herbeData.niveau}, Brins: ${brins})`;
}
list['Autre'] = 'Autre (Bonus: variable, Brins: variable)'
return list;
}
/* -------------------------------------------- */
static updatePotionData( formData ) {
formData.herbesSoins = this.buildHerbesList(this.herbesSoins, 12);
formData.herbesRepos = this.buildHerbesList(this.herbesRepos, 7);
formData.jourMoisOptions = Array(28).fill().map((item, index) => 1 + index);
formData.dateActuelle = game.system.rdd.calendrier.getDateFromIndex();
formData.splitDate = game.system.rdd.calendrier.getNumericDateFromIndex(formData.data.prdate);
if (formData.data.categorie.includes('Soin') ) {
formData.isHerbe = true;
this.computeHerbeBonus(formData, this.herbesSoins, 12);
} else if (formData.data.categorie.includes('Repos')) {
formData.isRepos = true;
this.computeHerbeBonus(formData, this.herbesRepos, 7);
}
}
/* -------------------------------------------- */
static calculePointsRepos( data ) {
return data.herbebonus * data.pr;
}
/* -------------------------------------------- */
static calculePointsGuerison( data ){
return data.herbebonus * data.pr;
}
/* -------------------------------------------- */
static computeHerbeBonus( formData, herbesList, max) {
if ( Number(formData.data.herbebrins) ) {
let herbe = herbesList.find(item => item.name.toLowerCase() == formData.data.herbe.toLowerCase() );
if( herbe ) {
let herbeData = Misc.templateData(herbe);
let brinsBase = max - herbeData.niveau;
//console.log(herbeData, brinsBase, formData.data.herbebrins);
formData.data.herbebonus = Math.max(herbeData.niveau - Math.max(brinsBase - formData.data.herbebrins, 0), 0);
}
}
}
}

View File

@ -9,12 +9,12 @@ export class RdDHotbar {
*/ */
static initDropbar( ) { static initDropbar( ) {
Hooks.on("hotbarDrop", async (bar, data, slot) => { Hooks.on("hotbarDrop", async (bar, documentData, slot) => {
// Create item macro if rollable item - weapon, spell, prayer, trait, or skill // Create item macro if rollable item - weapon, spell, prayer, trait, or skill
if (data.type == "Item") { if (documentData.type == "Item") {
if (data.data.type != "arme" && data.data.type != "competence" ) if (documentData.data.type != "arme" && documentData.data.type != "competence" )
return return
let item = data.data let item = documentData.data
let command = `game.system.rdd.RdDHotbar.rollMacro("${item.name}", "${item.type}");`; let command = `game.system.rdd.RdDHotbar.rollMacro("${item.name}", "${item.type}");`;
let macro = game.macros.entities.find(m => (m.name === item.name) && (m.command === command)); let macro = game.macros.entities.find(m => (m.name === item.name) && (m.command === command));
if (!macro) { if (!macro) {
@ -28,9 +28,9 @@ export class RdDHotbar {
game.user.assignHotbarMacro(macro, slot); game.user.assignHotbarMacro(macro, slot);
} }
// Create a macro to open the actor sheet of the actor dropped on the hotbar // Create a macro to open the actor sheet of the actor dropped on the hotbar
else if (data.type == "Actor") { else if (documentData.type == "Actor") {
let actor = game.actors.get(data.id); let actor = game.actors.get(documentData.id);
let command = `game.actors.get("${data.id}").sheet.render(true)` let command = `game.actors.get("${documentData.id}").sheet.render(true)`
let macro = game.macros.entities.find(m => (m.name === actor.name) && (m.command === command)); let macro = game.macros.entities.find(m => (m.name === actor.name) && (m.command === command));
if (!macro) { if (!macro) {
macro = await Macro.create({ macro = await Macro.create({
@ -43,9 +43,9 @@ export class RdDHotbar {
} }
} }
// Create a macro to open the journal sheet of the journal dropped on the hotbar // Create a macro to open the journal sheet of the journal dropped on the hotbar
else if (data.type == "JournalEntry") { else if (documentData.type == "JournalEntry") {
let journal = game.journal.get(data.id); let journal = game.journal.get(documentData.id);
let command = `game.journal.get("${data.id}").sheet.render(true)` let command = `game.journal.get("${documentData.id}").sheet.render(true)`
let macro = game.macros.entities.find(m => (m.name === journal.name) && (m.command === command)); let macro = game.macros.entities.find(m => (m.name === journal.name) && (m.command === command));
if (!macro) { if (!macro) {
macro = await Macro.create({ macro = await Macro.create({

View File

@ -22,13 +22,16 @@ import { RdDTokenHud } from "./rdd-token-hud.js";
import { RdDCommands } from "./rdd-commands.js"; import { RdDCommands } from "./rdd-commands.js";
import { RdDCombatManager, RdDCombat } from "./rdd-combat.js"; import { RdDCombatManager, RdDCombat } from "./rdd-combat.js";
import { ChatUtility } from "./chat-utility.js"; import { ChatUtility } from "./chat-utility.js";
import { RdDItemCompetence } from "./item-competence.js";
import { StatusEffects } from "./status-effects.js"; import { StatusEffects } from "./status-effects.js";
import { RddCompendiumOrganiser } from "./rdd-compendium-organiser.js"; import { RddCompendiumOrganiser } from "./rdd-compendium-organiser.js";
import { ReglesOptionelles } from "./regles-optionelles.js"; import { ReglesOptionelles } from "./regles-optionelles.js";
import { TMRRencontres } from "./tmr-rencontres.js"; import { TMRRencontres } from "./tmr-rencontres.js";
import { RdDHotbar } from "./rdd-hotbar-drop.js" import { RdDHotbar } from "./rdd-hotbar-drop.js"
import { EffetsDraconiques } from "./tmr/effets-draconiques.js"; import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
import { RdDHerbes } from "./rdd-herbes.js";
import { RdDItem } from "./item.js";
import { RdDDice } from "./rdd-dice.js";
import { RdDSigneDraconiqueItemSheet } from "./item-signedraconique-sheet.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Foundry VTT Initialization */ /* Foundry VTT Initialization */
@ -115,7 +118,21 @@ Hooks.once("init", async function () {
config: true, config: true,
default: true, default: true,
type: Boolean type: Boolean
}); });
/* -------------------------------------------- */
game.settings.register("foundryvtt-reve-de-dragon", "appliquer-famine-soif", {
name: "Notifier de la famine et la soif pour",
hint: "Indique si les cas de famine et de soif seront indiqués durant Château Dormant",
scope: "world",
config: true,
type: String,
choices: {
"aucun": "ni la famine, ni la soif",
"famine": "seulement la famine",
"famine-soif": "la famine et la soif",
},
default: "aucun"
});
/* -------------------------------------------- */ /* -------------------------------------------- */
// Set an initiative formula for the system // Set an initiative formula for the system
@ -125,15 +142,17 @@ Hooks.once("init", async function () {
}; };
/* -------------------------------------------- */ /* -------------------------------------------- */
game.socket.on("system.foundryvtt-reve-de-dragon", data => { game.socket.on("system.foundryvtt-reve-de-dragon", sockmsg => {
RdDUtility.onSocketMesssage(data); RdDUtility.onSocketMesssage(sockmsg);
RdDCombat.onSocketMessage(data); RdDCombat.onSocketMessage(sockmsg);
ChatUtility.onSocketMessage(data); ChatUtility.onSocketMessage(sockmsg);
RdDActor.onSocketMessage(sockmsg);
}); });
/* -------------------------------------------- */ /* -------------------------------------------- */
// Define custom Entity classes // Define custom Entity classes
CONFIG.Actor.entityClass = RdDActor; CONFIG.Actor.documentClass = RdDActor;
CONFIG.Item.documentClass = RdDItem;
CONFIG.RDD = { CONFIG.RDD = {
resolutionTable: RdDResolutionTable.resolutionTable, resolutionTable: RdDResolutionTable.resolutionTable,
carac_array: RdDUtility.getCaracArray(), carac_array: RdDUtility.getCaracArray(),
@ -149,17 +168,24 @@ Hooks.once("init", async function () {
Actors.registerSheet("foundryvtt-reve-de-dragon", RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true }); Actors.registerSheet("foundryvtt-reve-de-dragon", RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true });
Actors.registerSheet("foundryvtt-reve-de-dragon", RdDActorEntiteSheet, { types: ["entite"], makeDefault: true }); Actors.registerSheet("foundryvtt-reve-de-dragon", RdDActorEntiteSheet, { types: ["entite"], makeDefault: true });
Items.unregisterSheet("core", ItemSheet); Items.unregisterSheet("core", ItemSheet);
Items.registerSheet("foundryvtt-reve-de-dragon", RdDSigneDraconiqueItemSheet, {
label: "Signe draconique",
types: ["signedraconique"],
makeDefault: true
});
Items.registerSheet("foundryvtt-reve-de-dragon", RdDItemSheet, { makeDefault: true }); Items.registerSheet("foundryvtt-reve-de-dragon", RdDItemSheet, { makeDefault: true });
CONFIG.Combat.entityClass = RdDCombatManager; CONFIG.Combat.documentClass = RdDCombatManager;
// préparation des différents modules // préparation des différents modules
ReglesOptionelles.init();
RdDUtility.init();
RdDDice.init();
RdDCommands.init(); RdDCommands.init();
RdDCombat.init(); RdDCombat.init();
RdDCombatManager.init(), RdDCombatManager.init();
RdDTokenHud.init(); RdDTokenHud.init();
RdDActor.init(); RdDActor.init();
RddCompendiumOrganiser.init(); RddCompendiumOrganiser.init();
ReglesOptionelles.init();
EffetsDraconiques.init() EffetsDraconiques.init()
TMRUtility.init(); TMRUtility.init();
TMRRencontres.init(); TMRRencontres.init();
@ -171,20 +197,21 @@ function messageDeBienvenue() {
if (game.user.isGM) { if (game.user.isGM) {
ChatUtility.removeChatMessageContaining('<div id="message-bienvenue-rdd">'); ChatUtility.removeChatMessageContaining('<div id="message-bienvenue-rdd">');
ChatMessage.create({ ChatMessage.create({
user: game.user._id, user: game.user.id,
content: `<div id="message-bienvenue-rdd"><span class="rdd-roll-part">Bienvenue dans le Rêve des Dragons !</span> content: `<div id="message-bienvenue-rdd"><span class="rdd-roll-part">Bienvenue dans le Rêve des Dragons !</span>
<br>Vous trouverez quelques informations pour démarrer dans ce document : @Compendium[foundryvtt-reve-de-dragon.rappel-des-regles.7uGrUHGdPu0EmIu2]{Documentation MJ/Joueurs} <br>Vous trouverez quelques informations pour démarrer dans ce document : @Compendium[foundryvtt-reve-de-dragon.rappel-des-regles.7uGrUHGdPu0EmIu2]{Documentation MJ/Joueurs}
<br>La commande <code>/aide</code> dans le chat permet de voir les commandes spécifiques à Rêve de Dragon.</div> <br>La commande <code>/aide</code> dans le chat permet de voir les commandes spécifiques à Rêve de Dragon.</div>
` }); ` });
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Foundry VTT Initialization */ /* Foundry VTT Initialization */
/* -------------------------------------------- */ /* -------------------------------------------- */
Hooks.once("ready", function () { Hooks.once("ready", function () {
StatusEffects.onReady(); StatusEffects.onReady();
RdDHerbes.initializeHerbes();
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Affiche/Init le calendrier */ /* Affiche/Init le calendrier */
@ -202,7 +229,7 @@ Hooks.once("ready", function () {
ui.notifications.info("Attention ! Vous n'êtes connecté à aucun personnage !"); ui.notifications.info("Attention ! Vous n'êtes connecté à aucun personnage !");
ChatMessage.create({ ChatMessage.create({
content: "<b>ATTENTION</b> Le joueur " + game.user.name + " n'est connecté à aucun personnage !", content: "<b>ATTENTION</b> Le joueur " + game.user.name + " n'est connecté à aucun personnage !",
user: game.user._id user: game.user.id
}); });
//whisper: [ ChatMessage.getWhisperRecipients("GM") ] } ); //whisper: [ ChatMessage.getWhisperRecipients("GM") ] } );
} }
@ -211,7 +238,12 @@ Hooks.once("ready", function () {
}); });
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Foundry VTT Initialization */ /* Dice-so-nice ready */
/* -------------------------------------------- */
Hooks.once('diceSoNiceReady', (dice3d) => RdDDice.diceSoNiceReady(dice3d));
/* -------------------------------------------- */
/* Foundry VTT chat message */
/* -------------------------------------------- */ /* -------------------------------------------- */
Hooks.on("chatMessage", (html, content, msg) => { Hooks.on("chatMessage", (html, content, msg) => {
if (content[0] == '/') { if (content[0] == '/') {
@ -224,8 +256,3 @@ Hooks.on("chatMessage", (html, content, msg) => {
return true; return true;
}); });
/* -------------------------------------------- */
Hooks.on("renderChatMessage", async (app, html, msg) => {
RdDUtility.onRenderChatMessage(app, html, msg);
});

View File

@ -1,14 +1,17 @@
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
const words = [ 'pore', 'pre', 'flor', 'lane', 'turlu', 'pin', 'a', 'alph', 'i', 'onse', 'iane', 'ane', 'zach', 'arri', 'ba', 'bo', 'bi', const words = [ 'pore', 'pre', 'flor', 'lane', 'turlu', 'pin', 'a', 'alph', 'i', 'onse', 'iane', 'ane', 'zach', 'arri', 'ba', 'bo', 'bi',
'alta', 'par', 'pir', 'zor', 'zir', 'de', 'pol', 'tran', 'no', 'la','al' , 'pul', 'one', 'ner', 'nur' ]; 'alta', 'par', 'pir', 'zor', 'zir', 'de', 'pol', 'tran', 'no', 'la', 'al' , 'pul', 'one', 'ner', 'nur', 'mac', 'mery',
'cat', 'do', 'di', 'der', 'er', 'el', 'far', 'fer', 'go', 'guer', 'hot', 'jor', 'jar', 'ji', 'kri', 'ket', 'lor', 'hur',
'lar', 'lir', 'lu', 'pot', 'pro', 'pra', 'pit', 'qua', 'qui', 're', 'ral', 'sal', 'sen', 'ted', 'to', 'ta', 'lars', 'ver',
'vin', 'ov', 'wal', 'ry', 'ly', '' ];
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDNameGen { export class RdDNameGen {
static getName( msg, params ) { static async getName( msg, params ) {
let name = Misc.upperFirst( Misc.rollOneOf(words) + Misc.rollOneOf(words) ) let name = Misc.upperFirst( await RdDDice.rollOneOf(words) + await RdDDice.rollOneOf(words) )
//console.log(name); //console.log(name);
ChatMessage.create( { content: `Nom : ${name}`, whisper: ChatMessage.getWhisperRecipients("GM") } ); ChatMessage.create( { content: `Nom : ${name}`, whisper: ChatMessage.getWhisperRecipients("GM") } );
} }

View File

@ -51,10 +51,8 @@ const reussites = [
{ code: "error", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: true, isETotal: true, ptTache: 0, ptQualite: 0, quality: "Jet de dés invalide", condition: (target, roll) => (roll <= 0 || roll > 100) } { code: "error", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: true, isETotal: true, ptTache: 0, ptQualite: 0, quality: "Jet de dés invalide", condition: (target, roll) => (roll <= 0 || roll > 100) }
]; ];
const reussiteInsuffisante = { code: "notSign", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: false, isETotal: false, ptTache: 0, ptQualite: -2, quality: "Réussite insuffisante", condition: (target, roll) => false }
/* -------------------------------------------- */ /* -------------------------------------------- */
const reussiteSignificative = reussites.find(r => r.code == "sign");
const reussiteNormale = reussites.find(r => r.code == "norm");
const echecNormal = reussites.find(r => r.code == "echec");
const caracMaximumResolution = 60; const caracMaximumResolution = 60;
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDResolutionTable { export class RdDResolutionTable {
@ -115,7 +113,7 @@ export class RdDResolutionTable {
this._updateChancesFactor(chances, diviseur); this._updateChancesFactor(chances, diviseur);
chances.showDice = showDice; chances.showDice = showDice;
let rolled = await this.rollChances(chances); let rolled = await this.rollChances(chances, diviseur);
rolled.caracValue = caracValue; rolled.caracValue = caracValue;
rolled.finalLevel = finalLevel; rolled.finalLevel = finalLevel;
rolled.bonus = bonus; rolled.bonus = bonus;
@ -150,12 +148,9 @@ export class RdDResolutionTable {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async rollChances(chances) { static async rollChances(chances, diviseur) {
let myRoll = new Roll("1d100").roll(); chances.roll = await RdDDice.rollTotal("1d100", {showDice:chances.showDice});
myRoll.showDice = chances.showDice; mergeObject(chances, this.computeReussite(chances, chances.roll, diviseur), { overwrite: true });
await RdDDice.show(myRoll);
chances.roll = myRoll.total;
mergeObject(chances, this.computeReussite(chances, chances.roll), { overwrite: true });
return chances; return chances;
} }
@ -216,8 +211,12 @@ export class RdDResolutionTable {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static computeReussite(chances, roll) { static computeReussite(chances, roll, diviseur) {
return reussites.find(x => x.condition(chances, roll)); const reussite = reussites.find(x => x.condition(chances, roll));
if (diviseur > 1 && reussite.code == 'norm') {
return reussiteInsuffisante;
}
return reussite;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -269,23 +268,23 @@ export class RdDResolutionTable {
/* -------------------------------------------- */ /* -------------------------------------------- */
static buildHTMLResults(caracValue, levelValue) { static buildHTMLResults(caracValue, levelValue) {
if ( caracValue == undefined || isNaN(caracValue )) caracValue = 10; if (caracValue == undefined || isNaN(caracValue)) caracValue = 10;
if ( levelValue == undefined || isNaN(levelValue )) levelValue = 0; if (levelValue == undefined || isNaN(levelValue)) levelValue = 0;
let cell = this.computeChances(caracValue, levelValue); let cell = this.computeChances(caracValue, levelValue);
cell.epart = cell.epart > 99 ? 'N/A' : cell.epart; cell.epart = cell.epart > 99 ? 'N/A' : cell.epart;
cell.etotal = cell.etotal > 100 ? 'N/A' : cell.etotal; cell.etotal = cell.etotal > 100 ? 'N/A' : cell.etotal;
cell.score = Math.min(cell.score, 99); cell.score = Math.min(cell.score, 99);
return ` return `
<span class="table-proba-reussite competence-label"> <span class="table-proba-reussite competence-label">
Particulière: <span class="rdd-roll-part">${cell.part}</span> Particulière: <span class="rdd-roll-part">${cell.part}</span>
- Significative: <span class="rdd-roll-sign">${cell.sign}</span> - Significative: <span class="rdd-roll-sign">${cell.sign}</span>
- Réussite: <span class="rdd-roll-norm">${cell.score}</span> - Réussite: <span class="rdd-roll-norm">${cell.score}</span>
- Echec Particulier: <span class="rdd-roll-epart">${cell.epart}</span> - Echec Particulier: <span class="rdd-roll-epart">${cell.epart}</span>
- Echec Total: <span class="rdd-roll-etotal">${cell.etotal}</span> - Echec Total: <span class="rdd-roll-etotal">${cell.etotal}</span>
</span> </span>
` `
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -7,17 +7,23 @@ export class RdDEncaisser extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(html, actor) { constructor(html, actor) {
// Common conf // Common conf
const buttonsCreatures = {
"mortel": { label: "mortel", callback: html => this.performEncaisser("mortel") },
"non-mortel": { label: "non-mortel", callback: html => this.performEncaisser("non-mortel") },
};
const buttonsEntitesCauchemar = {
"cauchemar": { label: "cauchemar", callback: html => this.performEncaisser("cauchemar") }
};
const buttons = actor.isEntiteCauchemar() ? buttonsEntitesCauchemar : buttonsCreatures;
let dialogConf = { let dialogConf = {
title: "Jet d'Encaissement", title: "Jet d'Encaissement",
content: html, content: html,
buttons: { buttons: buttons,
"mortel": { label: "mortel", callback: html => this.performEncaisser(html, "mortel") },
"non-mortel": { label: "non-mortel", callback: html => this.performEncaisser(html, "non-mortel") },
"cauchemar": { label: "cauchemar", callback: html => this.performEncaisser(html, "cauchemar") }
},
default: "coupMortel" default: "coupMortel"
} }
let dialogOptions = { let dialogOptions = {
classes: ["rdddialog"], classes: ["rdddialog"],
width: 320, width: 320,
@ -32,13 +38,15 @@ export class RdDEncaisser extends Dialog {
this.encaisserSpecial = "aucun"; this.encaisserSpecial = "aucun";
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
performEncaisser(html, mortalite = "mortel") { performEncaisser(mortalite) {
this.actor.encaisserDommages({ this.actor.encaisserDommages({
dmg:{ dmg: {
total: Number(this.modifier), total: Number(this.modifier),
encaisserSpecial: this.encaisserSpecial, encaisserSpecial: this.encaisserSpecial,
loc: { result: 0, label: "Corps" }, loc: { result: 0, label: "" },
mortalite: mortalite mortalite: mortalite
} }
}); });

View File

@ -8,51 +8,55 @@ import { Misc } from "./misc.js";
export class RdDRollDialogEthylisme extends Dialog { export class RdDRollDialogEthylisme extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(html, rollData, actor) { constructor(html, rollData, actor, onRoll) {
let myButtons = {
rollButton: { label: "Test d'éthylisme", callback: html => this.actor.performEthylisme(this.rollData) }
};
// Common conf // Common conf
let dialogConf = { content: html, title: "Test d'éthylisme", buttons: myButtons, default: "rollButton" }; let dialogConf = {
let dialogOptions = { classes: ["rdddialog"], width: 400, height: 220, 'z-index': 99999 } title: "Test d'éthylisme",
content: html,
default: "rollButton",
buttons: { "rollButton": { label: "Test d'éthylisme", callback: html => this.onButton(html) } }
};
let dialogOptions = { classes: ["rdddialog"], width: 400, height: 270, 'z-index': 99999 }
super(dialogConf, dialogOptions) super(dialogConf, dialogOptions)
//console.log("ETH", rollData); //console.log("ETH", rollData);
this.onRoll = onRoll;
this.rollData = rollData; this.rollData = rollData;
this.actor = actor; this.actor = actor;
} }
async onButton(html) {
this.onRoll(this.rollData);
}
/* -------------------------------------------- */ /* -------------------------------------------- */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.bringToTop(); // Ensure top level this.bringToTop(); // Ensure top level
// Get the rollData stuff // Get the rollData stuff
var rollData = this.rollData; var rollData = this.rollData;
var dialog = this;
function updateRollResult(rollData) {
rollData.finalLevel = Number(rollData.etat) + Number(rollData.forceAlcool) + rollData.diffNbDoses;
// Mise à jour valeurs
$("#roll-param").text(rollData.vieValue + " / " + Misc.toSignedString(rollData.finalLevel));
$(".table-resolution").remove();
$("#resolutionTable").append(RdDResolutionTable.buildHTMLTableExtract(rollData.vieValue, rollData.finalLevel));
}
// Setup everything onload // Setup everything onload
$(function () { $(function () {
$("#forceAlcool").val(Misc.toInt(rollData.forceAlcool)); $("#forceAlcool").val(Misc.toInt(rollData.forceAlcool));
updateRollResult(rollData); dialog.updateRollResult();
}); });
// Update ! // Update !
html.find('#forceAlcool').change((event) => { html.find('#forceAlcool').change((event) => {
rollData.forceAlcool = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus rollData.forceAlcool = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus
updateRollResult(rollData); dialog.updateRollResult();
}); });
} }
async updateRollResult() {
this.rollData.finalLevel = Number(this.rollData.etat) + Number(this.rollData.forceAlcool) + this.rollData.diffNbDoses;
// Mise à jour valeurs
$("#roll-param").text(this.rollData.vie + " / " + Misc.toSignedString(this.rollData.finalLevel));
$(".table-resolution").remove();
}
} }

View File

@ -1,12 +1,12 @@
import { RollDataAjustements } from "./rolldata-ajustements.js"; import { RollDataAjustements } from "./rolldata-ajustements.js";
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemMeditation } from "./item-meditation.js";
import { RdDItemSort } from "./item-sort.js"; import { RdDItemSort } from "./item-sort.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDBonus } from "./rdd-bonus.js"; import { RdDBonus } from "./rdd-bonus.js";
import { RdDCarac } from "./rdd-carac.js"; import { RdDCarac } from "./rdd-carac.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { ReglesOptionelles } from "./regles-optionelles.js";
/** /**
* Extend the base Dialog entity to select roll parameters * Extend the base Dialog entity to select roll parameters
@ -64,13 +64,32 @@ export class RdDRoll extends Dialog {
canClose: true canClose: true
}; };
mergeObject(rollData, defaultRollData, { recursive: true, overwrite: false }); mergeObject(rollData, defaultRollData, { recursive: true, overwrite: false });
if (rollData.forceCarac) { if (rollData.forceCarac) {
rollData.carac = rollData.forceCarac; rollData.carac = rollData.forceCarac;
} }
rollData.diviseurSignificative = RdDRoll.getDiviseurSignificative(rollData);
RollDataAjustements.calcul(rollData, actor); RollDataAjustements.calcul(rollData, actor);
} }
/* -------------------------------------------- */
static getDiviseurSignificative(rollData) {
let facteurSign = 1;
if (rollData.surprise == 'demi') {
facteurSign *= 2;
}
if (rollData.needParadeSignificative) {
facteurSign *= 2;
}
if (RdDBonus.isDefenseAttaqueFinesse(rollData)) {
facteurSign *= 2;
}
if (!ReglesOptionelles.isUsing('tripleSignificative')) {
facteurSign = Math.min(facteurSign, 4);
}
return facteurSign;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static _ensureCorrectActions(actions) { static _ensureCorrectActions(actions) {
@ -122,7 +141,6 @@ export class RdDRoll extends Dialog {
await RdDResolutionTable.rollData(this.rollData); await RdDResolutionTable.rollData(this.rollData);
console.log("RdDRoll -=>", this.rollData, this.rollData.rolled); console.log("RdDRoll -=>", this.rollData, this.rollData.rolled);
this.actor.setRollWindowsOpened(false); this.actor.setRollWindowsOpened(false);
if (action.callbacks) if (action.callbacks)
for (let callback of action.callbacks) { for (let callback of action.callbacks) {
if (callback.condition == undefined || callback.condition(this.rollData)) { if (callback.condition == undefined || callback.condition(this.rollData)) {
@ -141,14 +159,17 @@ export class RdDRoll extends Dialog {
function onLoad() { function onLoad() {
let rollData = dialog.rollData; let rollData = dialog.rollData;
console.log(rollData);
// Update html, according to data // Update html, according to data
if (rollData.competence) { if (rollData.competence) {
const defaut_carac = Misc.templateData(rollData.competence).defaut_carac;
// Set the default carac from the competence item // Set the default carac from the competence item
rollData.selectedCarac = rollData.carac[rollData.competence.data.defaut_carac]; rollData.selectedCarac = rollData.carac[defaut_carac];
$("#carac").val(rollData.competence.data.defaut_carac); $("#carac").val(defaut_carac);
} }
if (rollData.selectedSort) { if (rollData.selectedSort) {
$("#draconic").val(rollData.selectedSort.data.listIndex); // Uniquement a la selection du sort, pour permettre de changer dialog.setSelectedSort(rollData.selectedSort);
$(".draconic").val(rollData.selectedSort.data.listIndex); // Uniquement a la selection du sort, pour permettre de changer
} }
RdDItemSort.setCoutReveReel(rollData.selectedSort); RdDItemSort.setCoutReveReel(rollData.selectedSort);
$("#diffLibre").val(Misc.toInt(rollData.diffLibre)); $("#diffLibre").val(Misc.toInt(rollData.diffLibre));
@ -173,17 +194,20 @@ export class RdDRoll extends Dialog {
this.rollData.selectedCarac = this.rollData.carac[caracKey]; // Update the selectedCarac this.rollData.selectedCarac = this.rollData.carac[caracKey]; // Update the selectedCarac
this.updateRollResult(); this.updateRollResult();
}); });
html.find('#draconic').change((event) => { html.find('.roll-draconic').change((event) => {
let draconicKey = Misc.toInt(event.currentTarget.value); let draconicKey = Misc.toInt(event.currentTarget.value);
this.rollData.competence = this.rollData.draconicList[draconicKey]; // Update the selectedCarac this.rollData.competence = this.rollData.draconicList[draconicKey]; // Update the selectedCarac
this.updateRollResult(); this.updateRollResult();
}); });
html.find('#sort').change((event) => { html.find('.roll-sort').change((event) => {
let sortKey = Misc.toInt(event.currentTarget.value); let sortKey = Misc.toInt(event.currentTarget.value);
this.rollData.selectedSort = this.rollData.sortList[sortKey]; // Update the selectedCarac this.setSelectedSort(this.rollData.sortList[sortKey]);
this.rollData.bonus = RdDItemSort.getCaseBonus(this.rollData.selectedSort, this.rollData.tmr.coord); this.updateRollResult();
RdDItemSort.setCoutReveReel(this.rollData.selectedSort); $("#diffLibre").val(this.rollData.diffLibre);
$("#draconic").val(this.rollData.selectedSort.data.listIndex); // Uniquement a la selection du sort, pour permettre de changer });
html.find('.roll-signedraconique').change((event) => {
let sortKey = Misc.toInt(event.currentTarget.value);
this.setSelectedSigneDraconique(this.rollData.signes[sortKey]);
this.updateRollResult(); this.updateRollResult();
}); });
html.find('#ptreve-variable').change((event) => { html.find('#ptreve-variable').change((event) => {
@ -196,16 +220,18 @@ export class RdDRoll extends Dialog {
this.rollData.dmg.mortalite = event.currentTarget.checked ? "non-mortel" : "mortel"; this.rollData.dmg.mortalite = event.currentTarget.checked ? "non-mortel" : "mortel";
this.updateRollResult(); this.updateRollResult();
}); });
html.find('#tactique-combat').change((event) => { html.find('.cuisine-proportions').change((event) => {
this.rollData.tactique = event.currentTarget.value; this.rollData.proportions = Number(event.currentTarget.value);
this.updateRollResult(); this.updateRollResult();
}); });
html.find('#useMalusSurenc').change((event) => { html.find('.select-by-name').change((event) => {
this.rollData.useMalusSurenc = event.currentTarget.checked; const attribute = event.currentTarget.attributes['name'].value;
this.rollData[attribute] = event.currentTarget.value;
this.updateRollResult(); this.updateRollResult();
}); });
html.find('#useMalusEncTotal').change((event) => { html.find('.checkbox-by-name').change((event) => {
this.rollData.useMalusEncTotal = event.currentTarget.checked; const attribute = event.currentTarget.attributes['name'].value;
this.rollData[attribute] = event.currentTarget.checked;
this.updateRollResult(); this.updateRollResult();
}); });
html.find('.imgAppelAuMoral').click((event) => { /* l'appel au moral, qui donne un bonus de +1 */ html.find('.imgAppelAuMoral').click((event) => { /* l'appel au moral, qui donne un bonus de +1 */
@ -232,6 +258,35 @@ export class RdDRoll extends Dialog {
}); });
} }
async setSelectedSort(sort) {
this.rollData.selectedSort = sort; // Update the selectedCarac
this.rollData.competence = RdDItemCompetence.getVoieDraconic(this.rollData.draconicList, sort.data.draconic);
this.rollData.bonus = RdDItemSort.getCaseBonus(sort, this.rollData.tmr.coord);
this.rollData.diffLibre = RdDItemSort.getDifficulte(sort, -7);
RdDItemSort.setCoutReveReel(sort);
const htmlSortDescription = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/partial-description-sort.html", { sort: sort });
$(".sort-ou-rituel").text(sort.data.isrituel ? "rituel" : "sort");
$(".bonus-case").text(`${this.rollData.bonus}%`);
$(".details-sort").remove();
$(".description-sort").append(htmlSortDescription);
$(".roll-draconic").val(sort.data.listIndex);
$(".div-sort-difficulte-fixe").text(Misc.toSignedString(sort.data.difficulte));
$(".div-sort-ptreve-fixe").text(sort.data.ptreve);
const diffVariable = RdDItemSort.isDifficulteVariable(sort);
const coutVariable = RdDItemSort.isCoutVariable(sort);
HtmlUtility._showControlWhen($(".div-sort-non-rituel"), !sort.data.isrituel);
HtmlUtility._showControlWhen($(".div-sort-difficulte-var"), diffVariable);
HtmlUtility._showControlWhen($(".div-sort-difficulte-fixe"), !diffVariable);
HtmlUtility._showControlWhen($(".div-sort-ptreve-var"), coutVariable);
HtmlUtility._showControlWhen($(".div-sort-ptreve-fixe"), !coutVariable);
}
async setSelectedSigneDraconique(signe){
this.rollData.signe = signe;
this.rollData.diffLibre = Misc.data(signe).data.difficulte,
$(".signe-difficulte").text(Misc.toSignedString(this.rollData.diffLibre));
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async updateRollResult() { async updateRollResult() {
let rollData = this.rollData; let rollData = this.rollData;
@ -243,12 +298,7 @@ export class RdDRoll extends Dialog {
let dmgText = Misc.toSignedString(rollData.dmg.total); let dmgText = Misc.toSignedString(rollData.dmg.total);
if (rollData.coupsNonMortels) { if (rollData.coupsNonMortels) {
dmgText = '(' + dmgText + ')'; dmgText = `(${dmgText}) non-mortel`
}
if (rollData.selectedSort) {
rollData.bonus = RdDItemSort.getCaseBonus(rollData.selectedSort, rollData.tmr.coord);
HtmlUtility._showControlWhen($("#div-sort-difficulte"), RdDItemSort.isDifficulteVariable(rollData.selectedSort))
HtmlUtility._showControlWhen($("#div-sort-ptreve"), RdDItemSort.isCoutVariable(rollData.selectedSort))
} }
RollDataAjustements.calcul(rollData, this.actor); RollDataAjustements.calcul(rollData, this.actor);
@ -260,9 +310,9 @@ export class RdDRoll extends Dialog {
HtmlUtility._showControlWhen($("#ajust-astrologique"), RdDResolutionTable.isAjustementAstrologique(rollData)); HtmlUtility._showControlWhen($("#ajust-astrologique"), RdDResolutionTable.isAjustementAstrologique(rollData));
// Mise à jour valeurs // Mise à jour valeurs
$("#compdialogTitle").text(this._getTitle(rollData)); $(".dialog-roll-title").text(this._getTitle(rollData));
$('#coupsNonMortels').prop('checked', rollData.coupsNonMortels); $('#coupsNonMortels').prop('checked', rollData.coupsNonMortels);
$("#dmg-arme-actor").text(dmgText); $(".dmg-arme-actor").text(dmgText);
$('.table-ajustement').remove(); $('.table-ajustement').remove();
$(".table-resolution").remove(); $(".table-resolution").remove();
$(".table-proba-reussite").remove(); $(".table-proba-reussite").remove();
@ -274,7 +324,7 @@ export class RdDRoll extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
async buildAjustements(rollData) { async buildAjustements(rollData) {
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-roll-ajustements.html`, rollData); const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.html`, rollData);
return html; return html;
} }
@ -328,9 +378,9 @@ export class RdDRoll extends Dialog {
const niveau = Misc.toSignedString(rollData.competence.data.niveau); const niveau = Misc.toSignedString(rollData.competence.data.niveau);
if (compName == carac) { if (compName == carac) {
// cas des créatures // cas des créatures
return carac + " " + niveau return carac + " Niveau " + niveau
} }
const armeTitle = (rollData.arme) ? " (" + rollData.arme.name + ") " : ""; const armeTitle = (rollData.arme) ? " (" + rollData.arme.name + ") " : "";
return carac + "/" + compName + armeTitle + " " + niveau return carac + "/" + compName + armeTitle + " Niveau " + niveau
} }
} }

View File

@ -5,33 +5,23 @@ export class RdDRollTables {
const pack = game.packs.get("foundryvtt-reve-de-dragon.tables-diverses"); const pack = game.packs.get("foundryvtt-reve-de-dragon.tables-diverses");
const index = await pack.getIndex(); const index = await pack.getIndex();
const entry = index.find(e => e.name === tableName); const entry = index.find(e => e.name === tableName);
const table = await pack.getEntity(entry._id); const table = await pack.getDocument(entry._id);
const draw = await table.draw({ displayChat: toChat, rollMode: "gmroll"}); const draw = await table.draw({ displayChat: toChat, rollMode: "gmroll"});
console.log("RdDRollTables", tableName, toChat, ":", draw); console.log("RdDRollTables", tableName, toChat, ":", draw);
return draw; return draw.results.length > 0 ? draw.results[0] : undefined;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async drawItemFromRollTable(tableName, toChat) { static async drawItemFromRollTable(tableName, toChat = false) {
const draw = await RdDRollTables.genericGetTableResult(tableName, toChat); const drawResult = await RdDRollTables.genericGetTableResult(tableName, toChat);
const drawnItemRef = draw.results.length > 0 ? draw.results[0] : undefined; const pack = game.packs.get(drawResult.data.collection);
if (drawnItemRef.collection) { return await pack.getDocument(drawResult.data.resultId);
const pack = game.packs.get(drawnItemRef.collection);
return await pack.getEntity(drawnItemRef.resultId);
}
ui.notifications.warn("le tirage ne correspond pas à une entrée d'un Compendium")
return drawnItemRef.text;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async drawTextFromRollTable(tableName, toChat) { static async drawTextFromRollTable(tableName, toChat) {
const draw = await RdDRollTables.genericGetTableResult(tableName, toChat); const drawResult = await RdDRollTables.genericGetTableResult(tableName, toChat);
const drawnItemRef = draw.results.length > 0 ? draw.results[0] : undefined; return drawResult.data.text;
if (drawnItemRef.collection) {
ui.notifications.warn("le tirage correspond à une entrée d'un Compendium, on attendait un texte")
return await pack.getEntity(drawnItemRef.resultId);
}
return drawnItemRef.text;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -10,8 +10,10 @@ import { Poetique } from "./poetique.js";
import { EffetsDraconiques } from "./tmr/effets-draconiques.js"; import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
import { PixiTMR } from "./tmr/pixi-tmr.js"; import { PixiTMR } from "./tmr/pixi-tmr.js";
import { Draconique } from "./tmr/draconique.js"; import { Draconique } from "./tmr/draconique.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { HtmlUtility } from "./html-utility.js";
import { ReglesOptionelles } from "./regles-optionelles.js";
import { RdDDice } from "./rdd-dice.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDTMRDialog extends Dialog { export class RdDTMRDialog extends Dialog {
@ -40,15 +42,16 @@ export class RdDTMRDialog extends Dialog {
const dialogOptions = { const dialogOptions = {
classes: ["tmrdialog"], classes: ["tmrdialog"],
width: 920, height: 980, width: 920, height: 980,
'z-index': 20 'z-index': 40
} }
super(dialogConf, dialogOptions); super(dialogConf, dialogOptions);
this.tmrdata = duplicate(tmrData); this.tmrdata = duplicate(tmrData);
this.actor = actor; this.actor = actor;
this.actor.tmrApp = this; // reference this app in the actor structure this.actor.tmrApp = this; // reference this app in the actor structure
this.viewOnly = tmrData.mode == "visu" this.viewOnly = tmrData.mode == "visu"
this.fatigueParCase = this.viewOnly ? 0 : this.actor.getTMRFatigue(); this.fatigueParCase = this.viewOnly || !ReglesOptionelles.isUsing("appliquer-fatigue") ? 0 : this.actor.getTMRFatigue();
this.cumulFatigue = 0; this.cumulFatigue = 0;
this.loadRencontres(); this.loadRencontres();
this.loadSortsReserve(); this.loadSortsReserve();
@ -58,24 +61,29 @@ export class RdDTMRDialog extends Dialog {
this.pixiApp = new PIXI.Application({ width: 720, height: 860 }); this.pixiApp = new PIXI.Application({ width: 720, height: 860 });
this.pixiTMR = new PixiTMR(this, this.pixiApp); this.pixiTMR = new PixiTMR(this, this.pixiApp);
this.cacheTMR = (game.user.isGM) ? false : actor.isTMRCache();
this.callbacksOnAnimate = []; this.callbacksOnAnimate = [];
if (!this.viewOnly) { if (!this.viewOnly) {
this.actor.setStatusDemiReve(true); this.actor.setStatusDemiReve(true);
this._tellToGM(this.actor.name + " monte dans les terres médianes (" + tmrData.mode + ")"); this._tellToGM(this.actor.name + " monte dans les terres médianes (" + tmrData.mode + ")");
} }
// load the texture we need // load the texture we need
this.pixiTMR.load((loader, resources) => this.createPixiSprites()); this.pixiTMR.load((loader, resources) => this.createPixiSprites());
} }
/* -------------------------------------------- */
loadCasesSpeciales() { loadCasesSpeciales() {
this.casesSpeciales = this.actor.data.items.filter(item => Draconique.isCaseTMR(item)); this.casesSpeciales = this.actor.data.items.filter(item => Draconique.isCaseTMR(item));
} }
/* -------------------------------------------- */
loadSortsReserve() { loadSortsReserve() {
this.sortsReserves = Misc.data(this.actor).data.reve.reserve.list; this.sortsReserves = Misc.data(this.actor).data.reve.reserve.list;
} }
/* -------------------------------------------- */
loadRencontres() { loadRencontres() {
this.rencontresExistantes = this.actor.getTMRRencontres(); this.rencontresExistantes = this.actor.getTMRRencontres();
} }
@ -83,9 +91,7 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
createPixiSprites() { createPixiSprites() {
EffetsDraconiques.carteTmr.createSprite(this.pixiTMR); EffetsDraconiques.carteTmr.createSprite(this.pixiTMR);
this.updateTokens(); this.updateTokens();
this.demiReve = this._tokenDemiReve(); this.demiReve = this._tokenDemiReve();
this._updateDemiReve(); this._updateDemiReve();
} }
@ -130,18 +136,50 @@ export class RdDTMRDialog extends Dialog {
return EffetsDraconiques.rencontre.token(this.pixiTMR, rencontre, () => rencontre.coord); return EffetsDraconiques.rencontre.token(this.pixiTMR, rencontre, () => rencontre.coord);
} }
_tokenCaseSpeciale(casetmr) { _tokenCaseSpeciale(casetmr) {
const draconique = Draconique.get(casetmr.data.specific); const caseData = Misc.data(casetmr);
return draconique?.token(this.pixiTMR, casetmr, () => casetmr.data.coord); const draconique = Draconique.get(caseData.data.specific);
return draconique?.token(this.pixiTMR, caseData, () => caseData.data.coord);
} }
_tokenSortEnReserve(sortEnReserve) { _tokenSortEnReserve(sortEnReserve) {
return EffetsDraconiques.sortReserve.token(this.pixiTMR, sortEnReserve.sort, () => sortEnReserve.coord); return EffetsDraconiques.sortReserve.token(this.pixiTMR, sortEnReserve.sort, () => sortEnReserve.coord);
} }
_tokenDemiReve() { _tokenDemiReve() {
return EffetsDraconiques.demiReve.token(this.pixiTMR, this.actor, () => Misc.data(this.actor).data.reve.tmrpos.coord); const actorData = Misc.data(this.actor);
return EffetsDraconiques.demiReve.token(this.pixiTMR, actorData, () => actorData.data.reve.tmrpos.coord);
} }
_updateDemiReve() { _updateDemiReve() {
this._setTokenPosition(this.demiReve); this.notifierResonanceSigneDraconique(this._getActorCoord());
if (!this.cacheTMR) {
this._setTokenPosition(this.demiReve);
}
}
_getActorCoord() {
return Misc.data(this.actor).data.reve.tmrpos.coord;
}
/* -------------------------------------------- */
async moveFromKey(move) {
let pos = TMRUtility.convertToCellPos(this._getActorCoord());
if (move == 'top') pos.y -= 1;
if (move == 'bottom') pos.y += 1;
if (move.includes('left')) pos.x -= 1;
if (move.includes('right')) pos.x += 1;
if (pos.x % 2 == 1) {
if (move == 'top-left') pos.y -= 1;
if (move == 'top-right') pos.y -= 1;
} else {
if (move == 'bottom-left') pos.y += 1;
if (move == 'bottom-right') pos.y += 1;
}
let targetCoord = TMRUtility.convertToTMRCoord(pos);
await this._deplacerDemiReve(targetCoord, 'normal');
this.checkQuitterTMR();
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -151,41 +189,72 @@ export class RdDTMRDialog extends Dialog {
document.getElementById("tmrrow1").insertCell(0).append(this.pixiApp.view); document.getElementById("tmrrow1").insertCell(0).append(this.pixiApp.view);
if (this.viewOnly) { if (this.viewOnly) {
html.find('#lancer-sort').remove(); html.find('.lancer-sort').remove();
} html.find('.lire-signe-draconique').remove();
else {
// Roll Sort
html.find('#lancer-sort').click((event) => {
this.actor.rollUnSort(Misc.data(this.actor).data.reve.tmrpos.coord);
});
}
if (this.viewOnly) {
return; return;
} }
HtmlUtility._showControlWhen($(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue"));
HtmlUtility._showControlWhen($(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(this._getActorCoord()));
// Roll Sort
html.find('.lancer-sort').click((event) => {
this.actor.rollUnSort(this._getActorCoord());
});
html.find('.lire-signe-draconique').click((event) => {
this.actor.rollLireSigneDraconique(this._getActorCoord());
});
html.find('#dir-top').click((event) => {
this.moveFromKey("top");
});
html.find('#dir-top-left').click((event) => {
this.moveFromKey("top-left");
});
html.find('#dir-top-right').click((event) => {
this.moveFromKey("top-right");
});
html.find('#dir-bottom-left').click((event) => {
this.moveFromKey("bottom-left");
});
html.find('#dir-bottom-right').click((event) => {
this.moveFromKey("bottom-right");
});
html.find('#dir-bottom').click((event) => {
this.moveFromKey("bottom");
});
// Gestion du cout de montée en points de rêve // Gestion du cout de montée en points de rêve
let reveCout = ((this.tmrdata.isRapide && !EffetsDraconiques.isDeplacementAccelere(this.actor)) ? -2 : -1) let reveCout = ((this.tmrdata.isRapide && !EffetsDraconiques.isDeplacementAccelere(this.actor)) ? -2 : -1) - this.actor.countMonteeLaborieuse();
- this.actor.countMonteeLaborieuse(); if (ReglesOptionelles.isUsing("appliquer-fatigue")) {
this.cumulFatigue += this.fatigueParCase; this.cumulFatigue += this.fatigueParCase;
}
await this.actor.reveActuelIncDec(reveCout); await this.actor.reveActuelIncDec(reveCout);
// Le reste... // Le reste...
this.updateValuesDisplay(); this.updateValuesDisplay();
let tmr = TMRUtility.getTMR(Misc.data(this.actor).data.reve.tmrpos.coord); let tmr = TMRUtility.getTMR(this._getActorCoord());
await this.manageRencontre(tmr, () => { await this.manageRencontre(tmr, () => {
this.postRencontre(tmr); this.postRencontre(tmr);
}); });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
updateValuesDisplay() { async updateValuesDisplay() {
let ptsreve = document.getElementById("tmr-pointsreve-value"); const coord = this._getActorCoord();
const actorData = Misc.data(this.actor); const actorData = Misc.data(this.actor);
HtmlUtility._showControlWhen($(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(coord));
let ptsreve = document.getElementById("tmr-pointsreve-value");
ptsreve.innerHTML = actorData.data.reve.reve.value; ptsreve.innerHTML = actorData.data.reve.reve.value;
let tmrpos = document.getElementById("tmr-pos"); let tmrpos = document.getElementById("tmr-pos");
let tmr = TMRUtility.getTMR(actorData.data.reve.tmrpos.coord); if (this.cacheTMR) {
tmrpos.innerHTML = actorData.data.reve.tmrpos.coord + " (" + tmr.label + ")"; tmrpos.innerHTML = '?? (' + TMRUtility.getTMRType(coord) + ')';
} else {
tmrpos.innerHTML = coord + " (" + TMRUtility.getTMRLabel(coord) + ")";
}
let etat = document.getElementById("tmr-etatgeneral-value"); let etat = document.getElementById("tmr-etatgeneral-value");
etat.innerHTML = this.actor.getEtatGeneral(); etat.innerHTML = this.actor.getEtatGeneral();
@ -193,9 +262,11 @@ export class RdDTMRDialog extends Dialog {
let refoulement = document.getElementById("tmr-refoulement-value"); let refoulement = document.getElementById("tmr-refoulement-value");
refoulement.innerHTML = actorData.data.reve.refoulement.value; refoulement.innerHTML = actorData.data.reve.refoulement.value;
let fatigueItem = document.getElementById("tmr-fatigue-table"); if (ReglesOptionelles.isUsing("appliquer-fatigue")) {
//console.log("Refresh : ", actorData.data.sante.fatigue.value); let fatigueItem = document.getElementById("tmr-fatigue-table");
fatigueItem.innerHTML = "<table class='table-fatigue'>" + RdDUtility.makeHTMLfatigueMatrix(actorData.data.sante.fatigue.value, actorData.data.sante.endurance.max).html() + "</table>"; //console.log("Refresh : ", actorData.data.sante.fatigue.value);
fatigueItem.innerHTML = "<table class='table-fatigue'>" + RdDUtility.makeHTMLfatigueMatrix(actorData.data.sante.fatigue.value, actorData.data.sante.endurance.max).html() + "</table>";
}
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -208,7 +279,6 @@ export class RdDTMRDialog extends Dialog {
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async derober() { async derober() {
await this.actor.addTMRRencontre(this.currentRencontre); await this.actor.addTMRRencontre(this.currentRencontre);
@ -216,6 +286,7 @@ export class RdDTMRDialog extends Dialog {
this._tellToGM(this.actor.name + " s'est dérobé et quitte les TMR."); this._tellToGM(this.actor.name + " s'est dérobé et quitte les TMR.");
this.close(); this.close();
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async refouler() { async refouler() {
this._tellToGM(this.actor.name + " a refoulé : " + this.currentRencontre.name); this._tellToGM(this.actor.name + " a refoulé : " + this.currentRencontre.name);
@ -259,12 +330,14 @@ export class RdDTMRDialog extends Dialog {
this.rencontreState = state; this.rencontreState = state;
} }
/* -------------------------------------------- */
async choisirCasePortee(coord, portee) { async choisirCasePortee(coord, portee) {
// Récupère la liste des cases à portées // Récupère la liste des cases à portées
let locList = TMRUtility.getTMRPortee(coord, portee); let locList = TMRUtility.getTMRPortee(coord, portee);
this.colorierZoneRencontre(locList); this.colorierZoneRencontre(locList);
} }
/* -------------------------------------------- */
async choisirCaseType(type) { async choisirCaseType(type) {
const locList = TMRUtility.filterTMR(it => it.type == type).map(it => it.coord); const locList = TMRUtility.filterTMR(it => it.type == type).map(it => it.coord);
this.colorierZoneRencontre(locList); this.colorierZoneRencontre(locList);
@ -279,7 +352,7 @@ export class RdDTMRDialog extends Dialog {
return true; return true;
} }
const resteAvantInconscience = this.actor.getFatigueMax() - this.actor.getFatigueActuelle() - this.cumulFatigue; const resteAvantInconscience = this.actor.getFatigueMax() - this.actor.getFatigueActuelle() - this.cumulFatigue;
if (resteAvantInconscience <= 0) { if (ReglesOptionelles.isUsing("appliquer-fatigue") && resteAvantInconscience <= 0) {
this._tellToGM("Vous vous écroulez de fatigue : vous quittez les Terres médianes !"); this._tellToGM("Vous vous écroulez de fatigue : vous quittez les Terres médianes !");
this.quitterLesTMRInconscient(); this.quitterLesTMRInconscient();
return true; return true;
@ -292,6 +365,7 @@ export class RdDTMRDialog extends Dialog {
return false; return false;
} }
/* -------------------------------------------- */
async quitterLesTMRInconscient() { async quitterLesTMRInconscient() {
if (this.currentRencontre?.isPersistant) { if (this.currentRencontre?.isPersistant) {
await this.refouler(); await this.refouler();
@ -312,35 +386,35 @@ export class RdDTMRDialog extends Dialog {
rencontre: this.currentRencontre, rencontre: this.currentRencontre,
nbRounds: 1, nbRounds: 1,
canClose: false, canClose: false,
tmr: TMRUtility.getTMR(Misc.data(this.actor).data.reve.tmrpos.coord) tmr: TMRUtility.getTMR(this._getActorCoord())
} }
await this._tentativeMaitrise(rencontreData); await this._tentativeMaitrise(rencontreData);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async _tentativeMaitrise(rencontreData, presentCite) { async _tentativeMaitrise(rencData, presentCite) {
console.log("-> matriser", rencontreData); console.log("-> matriser", rencData);
rencontreData.reve = this.actor.getReveActuel(); rencData.reve = this.actor.getReveActuel();
rencontreData.etat = this.actor.getEtatGeneral(); rencData.etat = this.actor.getEtatGeneral();
RollDataAjustements.calcul(rencontreData, this.actor); RollDataAjustements.calcul(rencData, this.actor);
rencontreData.rolled = rencontreData.presentCite rencData.rolled = rencData.presentCite
? this._rollPresentCite(rencontreData) ? this._rollPresentCite(rencData)
: await RdDResolutionTable.roll(rencontreData.reve, RollDataAjustements.sum(rencontreData.ajustements)); : await RdDResolutionTable.roll(rencData.reve, RollDataAjustements.sum(rencData.ajustements));
let postProcess = await TMRRencontres.gererRencontre(this, rencontreData); let postProcess = await TMRRencontres.gererRencontre(this, rencData);
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-rencontre-tmr.html`, rencontreData) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-rencontre-tmr.html`, rencData)
}); });
if (postProcess) { if (postProcess) {
/** Gère les rencontres avec du post-processing (passeur, messagers, tourbillons, ...) */ /** Gère les rencontres avec du post-processing (passeur, messagers, tourbillons, ...) */
await postProcess(this, rencontreData); await postProcess(this, rencData);
} }
else { else {
this.currentRencontre = undefined; this.currentRencontre = undefined;
@ -350,16 +424,19 @@ export class RdDTMRDialog extends Dialog {
if (this.checkQuitterTMR()) { if (this.checkQuitterTMR()) {
return; return;
} }
else if (rencontreData.rolled.isEchec && rencontreData.rencontre.isPersistant) { else if (rencData.rolled.isEchec && rencData.rencontre.isPersistant) {
setTimeout(() => { setTimeout(() => {
rencontreData.nbRounds++; rencData.nbRounds++;
this.cumulFatigue += this.fatigueParCase; if (ReglesOptionelles.isUsing("appliquer-fatigue")) {
this._tentativeMaitrise(rencontreData); this.cumulFatigue += this.fatigueParCase;
this._deleteTmrMessages(rencontreData.actor, rencontreData.nbRounds); }
this._tentativeMaitrise(rencData);
this._deleteTmrMessages(rencData.actor, rencData.nbRounds);
}, 2000); }, 2000);
} }
} }
/* -------------------------------------------- */
_rollPresentCite(rencontreData) { _rollPresentCite(rencontreData) {
let rolled = RdDResolutionTable.computeChances(rencontreData.reve, 0); let rolled = RdDResolutionTable.computeChances(rencontreData.reve, 0);
mergeObject(rolled, { caracValue: rencontreData.reve, finalLevel: 0, roll: rolled.score }); mergeObject(rolled, { caracValue: rencontreData.reve, finalLevel: 0, roll: rolled.score });
@ -383,17 +460,17 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
_tellToUser(message) { _tellToUser(message) {
ChatMessage.create({ content: message, user: game.user._id, whisper: [game.user._id] }); ChatMessage.create({ content: message, user: game.user.id, whisper: [game.user.id] });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_tellToGM(message) { _tellToGM(message) {
ChatMessage.create({ content: message, user: game.user._id, whisper: ChatMessage.getWhisperRecipients("GM") }); ChatMessage.create({ content: message, user: game.user.id, whisper: ChatMessage.getWhisperRecipients("GM") });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_tellToUserAndGM(message) { _tellToUserAndGM(message) {
ChatMessage.create({ content: message, user: game.user._id, whisper: [game.user._id].concat(ChatMessage.getWhisperRecipients("GM")) }); ChatMessage.create({ content: message, user: game.user.id, whisper: [game.user.id].concat(ChatMessage.getWhisperRecipients("GM")) });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -420,6 +497,7 @@ export class RdDTMRDialog extends Dialog {
} }
} }
/* -------------------------------------------- */
_presentCite(tmr, postRencontre) { _presentCite(tmr, postRencontre) {
const presentCite = this.casesSpeciales.find(c => EffetsDraconiques.presentCites.isCase(c, tmr.coord)); const presentCite = this.casesSpeciales.find(c => EffetsDraconiques.presentCites.isCase(c, tmr.coord));
if (presentCite) { if (presentCite) {
@ -429,6 +507,7 @@ export class RdDTMRDialog extends Dialog {
return presentCite; return presentCite;
} }
/* -------------------------------------------- */
async _utiliserPresentCite(presentCite, typeRencontre, tmr, postRencontre) { async _utiliserPresentCite(presentCite, typeRencontre, tmr, postRencontre) {
this.currentRencontre = TMRRencontres.getRencontre(typeRencontre); this.currentRencontre = TMRRencontres.getRencontre(typeRencontre);
await TMRRencontres.evaluerForceRencontre(this.currentRencontre); await TMRRencontres.evaluerForceRencontre(this.currentRencontre);
@ -457,11 +536,12 @@ export class RdDTMRDialog extends Dialog {
if (rencontre) { if (rencontre) {
return rencontre; return rencontre;
} }
let myRoll = new Roll("1d7").evaluate().total; let myRoll = await RdDDice.rollTotal("1d7");
if (TMRUtility.isForceRencontre() || myRoll == 7) { if (TMRUtility.isForceRencontre() || myRoll == 7) {
return await this.rencontreTMRRoll(tmr, this.actor.isRencontreSpeciale()); return await this.rencontreTMRRoll(tmr, this.actor.isRencontreSpeciale());
} }
this._tellToUser(myRoll + ": Pas de rencontre en " + tmr.label + " (" + tmr.coord + ")"); let locTMR = (this.cacheTMR) ? "??" : tmr.label + " (" + tmr.coord + ")";
this._tellToUser(myRoll + ": Pas de rencontre en " + locTMR);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -517,7 +597,7 @@ export class RdDTMRDialog extends Dialog {
await this._rollMaitriseCaseHumide(rollData); await this._rollMaitriseCaseHumide(rollData);
return; return;
} }
rollData.poesie = Poetique.getExtrait(); rollData.poesie = await Poetique.getExtrait();
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData)
@ -627,13 +707,14 @@ export class RdDTMRDialog extends Dialog {
await this._maitriserTMR(rollData, r => this._onResultatConquerir(r, options)); await this._maitriserTMR(rollData, r => this._onResultatConquerir(r, options));
} }
/* -------------------------------------------- */
async _onResultatConquerir(rollData, options) { async _onResultatConquerir(rollData, options) {
if (rollData.rolled.isETotal) { if (rollData.rolled.isETotal) {
rollData.souffle = await this.actor.ajouterSouffle({ chat: false }); rollData.souffle = await this.actor.ajouterSouffle({ chat: false });
} }
this.toclose = rollData.rolled.isEchec; this.toclose = rollData.rolled.isEchec;
rollData.poesie = Poetique.getExtrait(); rollData.poesie = await Poetique.getExtrait();
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData)
@ -653,7 +734,7 @@ export class RdDTMRDialog extends Dialog {
const dialog = await RdDRoll.create(this.actor, rollData, const dialog = await RdDRoll.create(this.actor, rollData,
{ {
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-maitrise-tmr.html', html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-maitrise-tmr.html',
options: { height: 350 }, options: { height: 420 },
close: html => { this.maximize(); } // Re-display TMR close: html => { this.maximize(); } // Re-display TMR
}, },
{ {
@ -667,6 +748,7 @@ export class RdDTMRDialog extends Dialog {
dialog.render(true); dialog.render(true);
} }
/* -------------------------------------------- */
async validerVisite(tmr) { async validerVisite(tmr) {
await EffetsDraconiques.pelerinage.onVisiteSupprimer(this.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)); await EffetsDraconiques.pelerinage.onVisiteSupprimer(this.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr));
await EffetsDraconiques.urgenceDraconique.onVisiteSupprimer(this.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)); await EffetsDraconiques.urgenceDraconique.onVisiteSupprimer(this.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr));
@ -781,8 +863,9 @@ export class RdDTMRDialog extends Dialog {
await tmrObject._onClickTMRPos(eventPos); // Vérifier l'état des compteurs reve/fatigue/vie await tmrObject._onClickTMRPos(eventPos); // Vérifier l'état des compteurs reve/fatigue/vie
} }
/* -------------------------------------------- */
async _onClickTMRPos(eventPos) { async _onClickTMRPos(eventPos) {
let currentPos = TMRUtility.convertToCellPos(Misc.data(this.actor).data.reve.tmrpos.coord); let currentPos = TMRUtility.convertToCellPos(this._getActorCoord());
console.log("deplacerDemiReve >>>>", currentPos, eventPos); console.log("deplacerDemiReve >>>>", currentPos, eventPos);
@ -826,24 +909,37 @@ export class RdDTMRDialog extends Dialog {
Si la case est le demi-rêve, ne pas lancer de sort. Si la case est le demi-rêve, ne pas lancer de sort.
Si un lancement de sort est en cours, trouver un moyen de réafficher cette fenêtre si on essaie de lancer un sort (ou bloquer le lancer de sort) Si un lancement de sort est en cours, trouver un moyen de réafficher cette fenêtre si on essaie de lancer un sort (ou bloquer le lancer de sort)
*/ */
this.notifierResonanceSigneDraconique(targetCoord);
await this.actor.rollUnSort(targetCoord); await this.actor.rollUnSort(targetCoord);
this.nettoyerRencontre(); this.nettoyerRencontre();
} }
/* -------------------------------------------- */
externalRefresh(tmrData) {
this.cacheTMR = (game.user.isGM) ? false : this.actor.isTMRCache();
this.createPixiSprites();
this.forceDemiRevePositionView();
this.updateValuesDisplay();
this.updateTokens();
console.log("TMR REFRESHED !!!");
}
/* -------------------------------------------- */
async _deplacerDemiReve(targetCoord, deplacementType) { async _deplacerDemiReve(targetCoord, deplacementType) {
if (this.currentRencontre != 'normal') { if (this.currentRencontre != 'normal') {
this.nettoyerRencontre(); this.nettoyerRencontre();
} }
let tmr = TMRUtility.getTMR(targetCoord); let tmr = TMRUtility.getTMR(targetCoord);
console.log("deplacerDemiReve", tmr, this); //console.log("deplacerDemiReve", tmr, this);
// Gestion cases spéciales type Trou noir, etc // Gestion cases spéciales type Trou noir, etc
tmr = await this.manageTmrInnaccessible(tmr); tmr = await this.manageTmrInnaccessible(tmr);
this.actor.updateCoordTMR(tmr.coord);
await this.actor.updateCoordTMR(tmr.coord); await this.actor.updateCoordTMR(tmr.coord);
this._updateDemiReve(); this._updateDemiReve();
this.cumulFatigue += this.fatigueParCase; if (ReglesOptionelles.isUsing("appliquer-fatigue")) {
this.cumulFatigue += this.fatigueParCase;
}
this.updateValuesDisplay(); this.updateValuesDisplay();
game.socket.emit("system.foundryvtt-reve-de-dragon", { game.socket.emit("system.foundryvtt-reve-de-dragon", {
msg: "msg_tmr_move", data: { msg: "msg_tmr_move", data: {
@ -860,6 +956,16 @@ export class RdDTMRDialog extends Dialog {
} }
} }
async notifierResonanceSigneDraconique(coord) {
if (this.actor.isResonanceSigneDraconique(coord)) {
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-resonance.html`, { alias: this.actor.name, typeTMR: TMRUtility.getTMRType(coord) })
});
}
}
/* -------------------------------------------- */
async postRencontre(tmr) { async postRencontre(tmr) {
if (!(this.viewOnly || this.currentRencontre)) { if (!(this.viewOnly || this.currentRencontre)) {
await this.manageCaseHumide(tmr); await this.manageCaseHumide(tmr);
@ -914,7 +1020,9 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
_setTokenPosition(token) { _setTokenPosition(token) {
this.pixiTMR.setPosition(token.sprite, TMRUtility.convertToCellPos(token.coordTMR())); if (!this.cacheTMR) {
this.pixiTMR.setPosition(token.sprite, TMRUtility.convertToCellPos(token.coordTMR()));
}
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -20,7 +20,7 @@ export class RdDTMRRencontreDialog extends Dialog {
const dialogOptions = { const dialogOptions = {
classes: ["tmrrencdialog"], classes: ["tmrrencdialog"],
width: 320, height: 240, width: 320, height: 240,
'z-index': 20 'z-index': 50
} }
super(dialogConf, dialogOptions); super(dialogConf, dialogOptions);

View File

@ -1,54 +1,57 @@
/* -------------------------------------------- */ /* -------------------------------------------- */
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js"; import { RdDCombatManager } from "./rdd-combat.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDTokenHud { export class RdDTokenHud {
static init(){ static init() {
// Integration du TokenHUD // Integration du TokenHUD
Hooks.on('renderTokenHUD', (app, html, data) => { RdDTokenHud.addTokenHudExtensions(app, html, data._id) }); Hooks.on('renderTokenHUD', (app, html, data) => { RdDTokenHud.addTokenHudExtensions(app, html, data._id) });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async removeExtensionHud( app, html, tokenId) { static async removeExtensionHud(app, html, tokenId) {
let combat = html.find('.control-icon.rdd-combat'); html.find('.control-icon.rdd-combat').remove();
combat.remove(); html.find('.control-icon.rdd-initiative').remove();
let initiative = html.find('.control-icon.rdd-initiative');
initiative.remove();
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async addExtensionHud( app, html, tokenId ) { static async addExtensionHud(app, html, tokenId) {
let token = canvas.tokens.get(tokenId); let token = canvas.tokens.get(tokenId);
let actor = token.actor; let actor = token.actor;
let combatant = game.combat.data.combatants.find(c => c.tokenId == token.data._id); let combatant = game.combat.combatants.find(c => Misc.data(c).tokenId == tokenId);
app.hasExtension = true; app.hasExtension = true;
let armesList = RdDCombatManager.buildListeActionsCombat(combatant) ; let armesList = RdDCombatManager.buildListeActionsCombat(combatant);
const hudData = { combatant: combatant, armes: armesList, const hudData = {
commandes: [{ name: 'Initiative +1', command: 'inc', value: 0.01}, { name: 'Initiative -1',command: 'dec', value: -0.01}] }; combatant: combatant, armes: armesList,
commandes: [{ name: 'Initiative +1', command: 'inc', value: 0.01 }, { name: 'Initiative -1', command: 'dec', value: -0.01 }]
};
const controlIconCombat = html.find('.control-icon[data-action=combat]');
// initiative // initiative
await RdDTokenHud._configureSubMenu(html.find('.control-icon.combat'), 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.html', hudData, await RdDTokenHud._configureSubMenu(controlIconCombat, 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.html', hudData,
(event) => { (event) => {
let initCommand = event.currentTarget.attributes['data-command'].value; let initCommand = event.currentTarget.attributes['data-command'].value;
let combatantId = event.currentTarget.attributes['data-combatant-id'].value; let combatantId = event.currentTarget.attributes['data-combatant-id'].value;
if ( !initCommand ) { if (!initCommand) {
let armeIndex = event.currentTarget.attributes['data-arme-id'].value; let armeIndex = event.currentTarget.attributes['data-arme-id'].value;
let arme = armesList[armeIndex]; let arme = armesList[armeIndex];
RdDCombatManager.rollInitiativeCompetence(combatantId, arme); RdDCombatManager.rollInitiativeCompetence(combatantId, arme);
} else if (initCommand == 'inc') { } else if (initCommand == 'inc') {
RdDCombatManager.incDecInit( combatantId, 0.01 ); RdDCombatManager.incDecInit(combatantId, 0.01);
} else if ( initCommand == 'dec') { } else if (initCommand == 'dec') {
RdDCombatManager.incDecInit( combatantId, -0.01 ); RdDCombatManager.incDecInit(combatantId, -0.01);
} }
}); });
const controlIconTarget = html.find('.control-icon[data-action=target]');
// combat // combat
await RdDTokenHud._configureSubMenu(html.find('.control-icon.target'), 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html', hudData, await RdDTokenHud._configureSubMenu(controlIconTarget, 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html', hudData,
(event) => { (event) => {
let armeIndex = event.currentTarget.attributes['data-arme-id'].value; let armeIndex = event.currentTarget.attributes['data-arme-id'].value;
let arme = armesList[armeIndex]; let arme = armesList[armeIndex];
@ -58,38 +61,35 @@ export class RdDTokenHud {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async addTokenHudExtensions(app, html, tokenId) { static async addTokenHudExtensions(app, html, tokenId) {
const controlIconCombat = html.find('.control-icon[data-action=combat]');
html.find('.control-icon.combat').click(event => { controlIconCombat.click(event => {
if ( event.currentTarget.className.includes('active')) { if (event.currentTarget.className.includes('active')) {
RdDTokenHud.removeExtensionHud( app, html, tokenId); RdDTokenHud.removeExtensionHud(app, html, tokenId);
} else { } else {
setTimeout( function() { RdDTokenHud.addExtensionHud( app, html, tokenId) } , 200 ); setTimeout(function () { RdDTokenHud.addExtensionHud(app, html, tokenId) }, 200);
} }
} ); });
let combatIcon = html.find('.control-icon.combat'); if (controlIconCombat.length>0 && controlIconCombat[0].className.includes('active')) {
if ( combatIcon[0].className.includes('active') ) { RdDTokenHud.addExtensionHud(app, html, tokenId);
RdDTokenHud.addExtensionHud( app, html, tokenId);
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async _configureSubMenu(insertionPoint, template, hudData, onMenuItem) { static async _configureSubMenu(insertionPoint, template, hudData, onMenuItem) {
const hud = $(await renderTemplate(template, hudData)); const hud = $(await renderTemplate(template, hudData));
const imgHud = hud.find('img.rdd-hud-togglebutton');
const list = hud.find('div.rdd-hud-list'); const list = hud.find('div.rdd-hud-list');
hud.toggleClass('active'); RdDTokenHud._toggleHudListActive(hud, list);
HtmlUtility._showControlWhen(list, hud.hasClass('active'));
hud.find('img.rdd-hud-togglebutton').click(event => RdDTokenHud._toggleHudListActive(hud, list));
imgHud.click(event => {
hud.toggleClass('active');
HtmlUtility._showControlWhen(list, hud.hasClass('active'));
});
list.find('.rdd-hud-menu').click(onMenuItem); list.find('.rdd-hud-menu').click(onMenuItem);
insertionPoint.after(hud); insertionPoint.after(hud);
} }
static _toggleHudListActive(hud, list) {
hud.toggleClass('active');
HtmlUtility._showControlWhen(list, hud.hasClass('active'));
}
} }

View File

@ -4,6 +4,10 @@ import { ChatUtility } from "./chat-utility.js";
import { RdDCombat } from "./rdd-combat.js"; import { RdDCombat } from "./rdd-combat.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { TMRUtility } from "./tmr-utility.js";
import { DialogItemAchat } from "./dialog-item-achat.js";
import { ReglesOptionelles } from "./regles-optionelles.js";
import { RdDDice } from "./rdd-dice.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
// This table starts at 0 -> niveau -10 // This table starts at 0 -> niveau -10
@ -92,6 +96,13 @@ const definitionsEncaissement = {
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDUtility { export class RdDUtility {
/* -------------------------------------------- */
static async init() {
Hooks.on("renderChatMessage", async (app, html, msg) => RdDUtility.onRenderChatMessage(app, html, msg));
Hooks.on('renderChatLog', (log, html, data) => RdDUtility.chatListeners(html));
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static async preloadHandlebarsTemplates() { static async preloadHandlebarsTemplates() {
const templatePaths = [ const templatePaths = [
@ -101,6 +112,13 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-vehicule-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/actor-vehicule-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-sheet-competence-partial.html', 'systems/foundryvtt-reve-de-dragon/templates/actor-sheet-competence-partial.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-sheet-categorie-competences-partial.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-sheet-oeuvre-partial.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-liste-blessures-partial.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-blessure-partial.html',
// Conteneur/item in Actor sheet
'systems/foundryvtt-reve-de-dragon/templates/actor-sheet-inventaire-conteneur.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-sheet-editor-notes-mj.html',
//Items //Items
'systems/foundryvtt-reve-de-dragon/templates/item-competence-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-competence-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-competencecreature-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-competencecreature-sheet.html',
@ -122,6 +140,8 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/item-ombre-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-ombre-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-monnaie-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-monnaie-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-meditation-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-meditation-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-nourritureboisson-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/competence-carac-defaut.html', 'systems/foundryvtt-reve-de-dragon/templates/competence-carac-defaut.html',
'systems/foundryvtt-reve-de-dragon/templates/competence-base.html', 'systems/foundryvtt-reve-de-dragon/templates/competence-base.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-aspect-tarot.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-aspect-tarot.html',
@ -130,6 +150,8 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-parade.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-parade.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-vehicule.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-vehicule.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-competence.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-competence.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-herbesoin-ingredient.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-potion.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-initpremierround.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-initpremierround.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-rarete.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-rarete.html',
'systems/foundryvtt-reve-de-dragon/templates/sort-draconic.html', 'systems/foundryvtt-reve-de-dragon/templates/sort-draconic.html',
@ -137,7 +159,6 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/niveau-ethylisme.html', 'systems/foundryvtt-reve-de-dragon/templates/niveau-ethylisme.html',
'systems/foundryvtt-reve-de-dragon/templates/casetmr-specific-list.html', 'systems/foundryvtt-reve-de-dragon/templates/casetmr-specific-list.html',
// Dialogs // Dialogs
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-ajustements.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-resolution.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-resolution.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-carac.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-carac.html',
@ -145,17 +166,22 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-encaisser.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-encaisser.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-meditation.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-meditation.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-surenc.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-enctotal.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-alchimie.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-alchimie.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-astrologie-joueur.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-astrologie-joueur.html',
// Partials
'systems/foundryvtt-reve-de-dragon/templates/partial-description-overflow.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-description-sort.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffLibre.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffCondition.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-surenc.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-enctotal.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-moral.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-select-carac.html',
// Calendrier // Calendrier
'systems/foundryvtt-reve-de-dragon/templates/calendar-template.html', 'systems/foundryvtt-reve-de-dragon/templates/calendar-template.html',
'systems/foundryvtt-reve-de-dragon/templates/calendar-editor-template.html', 'systems/foundryvtt-reve-de-dragon/templates/calendar-editor-template.html',
'systems/foundryvtt-reve-de-dragon/templates/heures-select-option.html', 'systems/foundryvtt-reve-de-dragon/templates/heures-select-option.html',
// Conteneur/item in Actor sheet
'systems/foundryvtt-reve-de-dragon/templates/actor-inventaire-conteneur.html',
'systems/foundryvtt-reve-de-dragon/templates/editor-notes-mj.html',
// HUD // HUD
'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.html', 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.html',
'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html', 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html',
@ -178,7 +204,10 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/chat-resultat-alchimie.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-resultat-alchimie.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-summary.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-summary.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-actor-competence-xp.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-actor-competence-xp.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-actor-carac-xp.html' 'systems/foundryvtt-reve-de-dragon/templates/chat-actor-carac-xp.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-potionenchantee-chateaudormant.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-fabriquer-potion-base.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html'
]; ];
Handlebars.registerHelper('upperFirst', str => Misc.upperFirst(str ?? 'Null')); Handlebars.registerHelper('upperFirst', str => Misc.upperFirst(str ?? 'Null'));
@ -187,10 +216,21 @@ export class RdDUtility {
Handlebars.registerHelper('un', str => Grammar.articleIndetermine(str)); Handlebars.registerHelper('un', str => Grammar.articleIndetermine(str));
Handlebars.registerHelper('accord', (genre, ...args) => Grammar.accord(genre, args)); Handlebars.registerHelper('accord', (genre, ...args) => Grammar.accord(genre, args));
Handlebars.registerHelper('buildConteneur', (objet) => { return RdDUtility.buildConteneur(objet); }); Handlebars.registerHelper('buildConteneur', (objet) => { return RdDUtility.buildConteneur(objet); });
Handlebars.registerHelper('caseTmr-label', coord => TMRUtility.getTMRLabel(coord));
Handlebars.registerHelper('caseTmr-type', coord => TMRUtility.getTMRType(coord));
Handlebars.registerHelper('equals', (a, b) => a == b);
return loadTemplates(templatePaths); return loadTemplates(templatePaths);
} }
/* -------------------------------------------- */
static buildListOptions(min, max) {
let options = ""
for (let i = min; i <= max; i++) {
options += `<option value="${i}">${i}</option>`
}
return options;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static checkNull(items) { static checkNull(items) {
@ -224,93 +264,73 @@ export class RdDUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static filterItemsPerTypeForSheet(formData) { static filterItemsPerTypeForSheet(formData) {
formData.data.materiel = this.checkNull(formData.itemsByType['objet']); formData.materiel = this.checkNull(formData.itemsByType['objet']);
formData.data.conteneurs = this.checkNull(formData.itemsByType['conteneur']); formData.conteneurs = this.checkNull(formData.itemsByType['conteneur']);
formData.data.armes = this.checkNull(formData.itemsByType['arme']); formData.armes = this.checkNull(formData.itemsByType['arme']);
formData.data.armures = this.checkNull(formData.itemsByType['armure']); formData.armures = this.checkNull(formData.itemsByType['armure']);
formData.data.livres = this.checkNull(formData.itemsByType['livre']); formData.livres = this.checkNull(formData.itemsByType['livre']);
formData.data.potions = this.checkNull(formData.itemsByType['potion']); formData.potions = this.checkNull(formData.itemsByType['potion']);
formData.data.ingredients = this.checkNull(formData.itemsByType['ingredient']); formData.ingredients = this.checkNull(formData.itemsByType['ingredient']);
formData.data.munitions = this.checkNull(formData.itemsByType['munition']); formData.munitions = this.checkNull(formData.itemsByType['munition']);
formData.data.herbes = this.checkNull(formData.itemsByType['herbe']); formData.herbes = this.checkNull(formData.itemsByType['herbe']);
formData.data.sorts = this.checkNull(formData.itemsByType['sort']); formData.sorts = this.checkNull(formData.itemsByType['sort']);
formData.data.queues = this.checkNull(formData.itemsByType['queue']); formData.signesdraconiques = this.checkNull(formData.itemsByType['signedraconique']);
formData.data.souffles = this.checkNull(formData.itemsByType['souffle']); formData.queues = this.checkNull(formData.itemsByType['queue']);
formData.data.ombres = this.checkNull(formData.itemsByType['ombre']); formData.souffles = this.checkNull(formData.itemsByType['souffle']);
formData.data.tetes = this.checkNull(formData.itemsByType['tete']); formData.ombres = this.checkNull(formData.itemsByType['ombre']);
formData.data.taches = this.checkNull(formData.itemsByType['tache']); formData.tetes = this.checkNull(formData.itemsByType['tete']);
formData.data.monnaie = this.checkNull(formData.itemsByType['monnaie']); formData.taches = this.checkNull(formData.itemsByType['tache']);
formData.data.meditations = this.checkNull(formData.itemsByType['meditation']); formData.monnaie = this.checkNull(formData.itemsByType['monnaie']);
formData.data.chants = this.checkNull(formData.itemsByType['chant']); formData.nourritureboissons = this.checkNull(formData.itemsByType['nourritureboisson']);
formData.data.danses = this.checkNull(formData.itemsByType['danse']); formData.meditations = this.checkNull(formData.itemsByType['meditation']);
formData.data.musiques = this.checkNull(formData.itemsByType['musique']); formData.chants = this.checkNull(formData.itemsByType['chant']);
formData.data.oeuvres = this.checkNull(formData.itemsByType['oeuvre']); formData.danses = this.checkNull(formData.itemsByType['danse']);
formData.data.jeux = this.checkNull(formData.itemsByType['jeu']); formData.musiques = this.checkNull(formData.itemsByType['musique']);
formData.data.recettescuisine = this.checkNull(formData.itemsByType['recettecuisine']); formData.oeuvres = this.checkNull(formData.itemsByType['oeuvre']);
formData.data.recettesAlchimiques = this.checkNull(formData.itemsByType['recettealchimique']); formData.jeux = this.checkNull(formData.itemsByType['jeu']);
formData.data.objets = formData.data.conteneurs.concat(formData.data.materiel) formData.recettescuisine = this.checkNull(formData.itemsByType['recettecuisine']);
.concat(formData.data.armes) formData.recettesAlchimiques = this.checkNull(formData.itemsByType['recettealchimique']);
.concat(formData.data.armures) formData.objets = formData.conteneurs.concat(formData.materiel)
.concat(formData.data.munitions) .concat(formData.armes)
.concat(formData.data.livres) .concat(formData.armures)
.concat(formData.data.potions) .concat(formData.munitions)
.concat(formData.data.herbes) .concat(formData.livres)
.concat(formData.data.ingredients); .concat(formData.potions)
formData.data.competences = (formData.itemsByType.competence??[]).concat(formData.itemsByType.competencecreature??[]); .concat(formData.herbes)
.concat(formData.ingredients)
.concat(formData.nourritureboissons);
formData.competences = (formData.itemsByType.competence ?? []).concat(formData.itemsByType.competencecreature ?? []);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async processItemDropEvent(actorSheet, event) { static buildArbreDeConteneurs(conteneurs, objets) {
let dragData = JSON.parse(event.dataTransfer.getData("text/plain")); let objetVersConteneur = {};
console.log(dragData, actorSheet.actor._id);
let dropID = $(event.target).parents(".item").attr("data-item-id"); // Only relevant if container drop
let objetId = dragData.id || dragData.data._id;
if (dragData.type == 'Item') {
if (dropID) { // Dropped over an item !!!
if (actorSheet.objetVersConteneur[objetId] != dropID && objetId != dropID) {
if (actorSheet.actor.validateConteneur(objetId, dropID) && actorSheet.actor.testConteneurCapacite(objetId, dropID)) {
await actorSheet.actor.enleverDeConteneur(objetId, actorSheet.objetVersConteneur[objetId]);
await actorSheet.actor.ajouterAConteneur(objetId, dropID);
}
}
}
if (dragData.actorId && dragData.actorId != actorSheet.actor._id) { // Un acteur est à l'origine de l'item -> deplacement
console.log("Moving objects");
actorSheet.actor.moveItemsBetweenActors(objetId, dragData.actorId);
return false;
}
actorSheet.actor.computeEncombrementTotalEtMalusArmure();
} else if (dragData.type == "Actor") {
actorSheet.actor.addSubacteur(objetId);
}
return true;
}
/* -------------------------------------------- */
static buildArbreDeConteneur(actorSheet, data) {
actorSheet.objetVersConteneur = {}; // Table de hash locale pour recupération rapide du conteneur parent (si existant)
// Attribution des objets aux conteneurs // Attribution des objets aux conteneurs
for (let conteneur of data.data.conteneurs) { for (let conteneur of conteneurs) {
conteneur.subItems = []; conteneur.subItems = [];
if (!conteneur.data.encTotal) conteneur.data.encTotal = 0; if (!conteneur.data.encTotal)
conteneur.data.encTotal = 0;
//conteneur.data.encTotal = ; Deja calculé //conteneur.data.encTotal = ; Deja calculé
if (conteneur.data.contenu) { if (conteneur.data.contenu) {
for (let id of conteneur.data.contenu) { for (let id of conteneur.data.contenu) {
let objet = data.data.objets.find(objet => (id == objet._id)); let objet = objets.find(objet => (id == objet._id));
if (objet) { if (objet) {
if (!objet.data.encombrement) objet.data.encombrement = 0; // Auto-fix if (!objet.data.encombrement)
objet.data.encombrement = 0; // Auto-fix
objet.estContenu = true; // Permet de filtrer ce qifui est porté dans le template objet.estContenu = true; // Permet de filtrer ce qifui est porté dans le template
actorSheet.objetVersConteneur[id] = conteneur._id; objetVersConteneur[id] = conteneur._id;
conteneur.data.encTotal += Number(objet.data.encombrement) * Number(((objet.data.quantite) ? objet.data.quantite : 1)); conteneur.data.encTotal += Number(objet.data.encombrement) * Number(((objet.data.quantite) ? objet.data.quantite : 1));
conteneur.subItems.push(objet); conteneur.subItems.push(objet);
} }
} }
} }
} }
// Construit la liste des conteneurs de niveau 1 (c'est à dire non contenu eux-même dans un conteneur) return objetVersConteneur;
let newConteneurs = data.data.conteneurs.filter(function (conteneur, index, arr) { return !conteneur.estContenu }); }
data.data.conteneurs = newConteneurs;
//console.log(newConteneurs); // Construit la liste des conteneurs de niveau 1 (c'est à dire non contenu eux-même dans un conteneur)
static conteneursRacine(conteneurs) {
return conteneurs.filter( (conteneur, index, arr) => !conteneur.estContenu);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -321,7 +341,7 @@ export class RdDUtility {
if (!niveau) niveau = 1; if (!niveau) niveau = 1;
objet.niveau = niveau; objet.niveau = niveau;
//console.log("OBJ:", objet); //console.log("OBJ:", objet);
let str = Handlebars.partials['systems/foundryvtt-reve-de-dragon/templates/actor-inventaire-conteneur.html']({ item: objet }); let str = Handlebars.partials['systems/foundryvtt-reve-de-dragon/templates/actor-sheet-inventaire-conteneur.html']({ item: objet });
if (objet.type == 'conteneur') { if (objet.type == 'conteneur') {
//console.log("ITEM DISPLAYED", objet ); //console.log("ITEM DISPLAYED", objet );
if (this.getAfficheContenu(objet._id)) { if (this.getAfficheContenu(objet._id)) {
@ -374,6 +394,14 @@ export class RdDUtility {
} }
return -7; return -7;
} }
static calculFatigueHtml(fatigue, endurance) {
return ReglesOptionelles.isUsing("appliquer-fatigue") ? {
malus: RdDUtility.calculMalusFatigue(fatigue, endurance),
html: "<table class='table-fatigue'>" + RdDUtility.makeHTMLfatigueMatrix(fatigue, endurance).html() + "</table>"
} : { malus:0, html:''};
}
/* -------------------------------------------- */ /* -------------------------------------------- */
// Build the nice (?) html table used to manage fatigue. // Build the nice (?) html table used to manage fatigue.
// max should be the endurance max value // max should be the endurance max value
@ -417,8 +445,8 @@ export class RdDUtility {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getLocalisation(type = 'personnage') { static async getLocalisation(type = 'personnage') {
let result = new Roll("1d20").roll().total; let result = await RdDDice.rollTotal("1d20");
let txt = "" let txt = ""
if (type == 'personnage') { if (type == 'personnage') {
if (result <= 3) txt = "Jambe, genou, pied, jarret"; if (result <= 3) txt = "Jambe, genou, pied, jarret";
@ -450,56 +478,35 @@ export class RdDUtility {
return duplicate(table[0]); return duplicate(table[0]);
} }
/* -------------------------------------------- */
static _evaluatePerte(formula, over20) {
console.log("_evaluatePerte", formula, over20);
let perte = new Roll(formula, { over20: over20 });
perte.evaluate();
return perte.total;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static currentFatigueMalus(value, max) { static currentFatigueMalus(value, max) {
max = Math.max(1, Math.min(max, 60)); if (ReglesOptionelles.isUsing("appliquer-fatigue")) {
value = Math.min(max * 2, Math.max(0, value)); max = Math.max(1, Math.min(max, 60));
value = Math.min(max * 2, Math.max(0, value));
let fatigueTab = fatigueMatrix[max];
let fatigueRem = value; let fatigueTab = fatigueMatrix[max];
for (let idx = 0; idx < fatigueTab.length; idx++) { let fatigueRem = value;
fatigueRem -= fatigueTab[idx]; for (let idx = 0; idx < fatigueTab.length; idx++) {
if (fatigueRem <= 0) { fatigueRem -= fatigueTab[idx];
return fatigueMalus[idx]; if (fatigueRem <= 0) {
return fatigueMalus[idx];
}
} }
return -7; // This is the max !
} }
return -7; // This is the max ! return 0;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async loadCompendiumNames(compendium) { static async loadCompendiumData(compendium) {
const pack = game.packs.get(compendium); const pack = game.packs.get(compendium);
let competences; return await pack?.getDocuments() ?? [];
await pack.getIndex().then(index => competences = index);
return competences;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async loadCompendium(compendium, filter = item => true) { static async loadCompendium(compendium, filter = item => true) {
if (!compendium){ let compendiumData = await RdDUtility.loadCompendiumData(compendium);
return []; return compendiumData.filter(filter);
}
let compendiumItems = await RdDUtility.loadCompendiumNames(compendium);
const pack = game.packs.get(compendium);
let list = [];
for (let compendiumItem of compendiumItems) {
await pack.getEntity(compendiumItem._id).then(it => {
const item = it.data;
if (filter(item)) {
list.push(item);
}
});
};
return list;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -521,16 +528,14 @@ export class RdDUtility {
case "msg_response_nombre_astral": case "msg_response_nombre_astral":
return RdDUtility.responseNombreAstral(sockmsg.data); return RdDUtility.responseNombreAstral(sockmsg.data);
case "msg_tmr_move": case "msg_tmr_move":
if (game.user.isGM) { let actor = game.actors.get(sockmsg.data.actorId);
let actor = game.actors.get(sockmsg.data.actorId); if (actor.isOwner || game.user.isGM ) {
actor.refreshTMRView(sockmsg.data.tmrPos); actor.refreshTMRView(sockmsg.data.tmrPos);
} }
break;
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async chatListeners(html) { static async chatListeners(html) {
RdDCombat.registerChatCallbacks(html); RdDCombat.registerChatCallbacks(html);
@ -550,24 +555,78 @@ export class RdDUtility {
let actor = game.actors.get(actorId); let actor = game.actors.get(actorId);
actor.tmrApp.lancerSortEnReserve(coord, sortId); actor.tmrApp.lancerSortEnReserve(coord, sortId);
}); });
// gestion bouton tchat Acheter
html.on("click", '.button-acheter', event => DialogItemAchat.onButtonAcheter(event));
// Gestion du bouton payer // Gestion du bouton payer
html.on("click", '#payer-button', event => { html.on("click", '.payer-button', event => {
let sumdenier = event.currentTarget.attributes['data-somme-denier'].value; let sumdenier = event.currentTarget.attributes['data-somme-denier']?.value ?? 0;
let quantite = event.currentTarget.attributes['data-quantite'].value; let quantite = event.currentTarget.attributes['data-quantite']?.value ?? 1;
let fromActorId = event.currentTarget.attributes['data-actor-id']?.value;
let jsondata = event.currentTarget.attributes['data-jsondata'] let jsondata = event.currentTarget.attributes['data-jsondata']
let objData let objData
if (jsondata) { if (jsondata) {
objData = JSON.parse(jsondata.value) objData = JSON.parse(jsondata.value)
} }
if (game.user.character) { let actor = RdDUtility.getSelectedActor("Pour effectuer le paiement:");
game.user.character.payerDenier(sumdenier, objData, quantite); if (actor) {
} else { actor.depenserDeniers(sumdenier, objData, quantite, fromActorId);
let msgPayer = "Vous devez avoir un acteur relié pour effectuer le paiement"; // TODO: diminuer la quantité ou supprimer le message
ChatMessage.create({ content: msgPayer, whisper: [game.user] }); // message: => document.querySelector("#chat-log > li:nth-child(61) > div > div > span > a")
// => ../../../..[@data-message-id]
let chatMessageId = RdDUtility.findChatMessageId(event.currentTarget);
if (chatMessageId) {
ChatUtility.removeChatMessageId(chatMessageId);
}
} }
}); });
} }
static findChatMessageId(current) {
return RdDUtility.getChatMessageId(RdDUtility.findChatMessage(current));
}
static getChatMessageId(node) {
return node?.attributes.getNamedItem('data-message-id')?.value;
}
static findChatMessage(current) {
return RdDUtility.findNodeMatching(current, it => it.classList.contains('chat-message') && it.attributes.getNamedItem('data-message-id'));
}
static findNodeMatching(current, predicate) {
if (current) {
if (predicate(current)) {
return current;
}
return RdDUtility.findNodeMatching(current.parentElement, predicate);
}
return undefined;
}
static getSelectedActor(msgPlayer = undefined) {
if (canvas.tokens.controlled.length == 1) {
let token = canvas.tokens.controlled[0];
if (token.actor && token.data.actorLink) {
return token.actor;
}
if (msgPlayer != undefined){
msgPlayer += "<br>le token sélectionné doit être lié à un personnage";
}
}
if (game.user.character) {
return game.user.character;
}
if (msgPlayer != undefined){
msgPlayer += "<br>vous pouvez sélectionner un seul token lié à un personnage";
msgPlayer += "<br>vous devez être connecté comme joueur avec un personnage sélectionné";
ui.notifications.warn(msgPlayer);
ChatMessage.create({ content: msgPlayer, whisper: [game.user] });
}
return undefined;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static createMonnaie(name, valeur_deniers, img = "", enc = 0.01) { static createMonnaie(name, valeur_deniers, img = "", enc = 0.01) {
let piece = { let piece = {
@ -599,14 +658,14 @@ export class RdDUtility {
let sumtotald = sumd + (sums * 100); let sumtotald = sumd + (sums * 100);
let msgPayer = "La somme de " + sums + " Sols et " + sumd + " Deniers est à payer, cliquer sur le lien ci-dessous si besoin.<br>"; let msgPayer = "La somme de " + sums + " Sols et " + sumd + " Deniers est à payer, cliquer sur le lien ci-dessous si besoin.<br>";
msgPayer += "<a id='payer-button' class='chat-card-button' data-somme-denier='" + sumtotald + "'>Payer</a>" msgPayer += "<a class='payer-button chat-card-button' data-somme-denier='" + sumtotald + "'>Payer</a>"
ChatMessage.create({ content: msgPayer }); ChatMessage.create({ content: msgPayer });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static chatDataSetup(content, modeOverride, isRoll = false, forceWhisper) { static chatDataSetup(content, modeOverride, isRoll = false, forceWhisper) {
let chatData = { let chatData = {
user: game.user._id, user: game.user.id,
rollMode: modeOverride || game.settings.get("core", "rollMode"), rollMode: modeOverride || game.settings.get("core", "rollMode"),
content: content content: content
}; };
@ -654,7 +713,7 @@ export class RdDUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async confirmerSuppression(actorSheet, li) { static async confirmerSuppression(actorSheet, li) {
let itemId = li.data("item-id"); let itemId = li.data("item-id");
let objet = actorSheet.actor.items.find(item => item._id == itemId); let objet = actorSheet.actor.getObjet(itemId);
let msgTxt = "<p>Etes vous certain de vouloir supprimer cet objet ?"; let msgTxt = "<p>Etes vous certain de vouloir supprimer cet objet ?";
let buttons = { let buttons = {
delete: { delete: {
@ -662,7 +721,7 @@ export class RdDUtility {
label: "Supprimer l'objet", label: "Supprimer l'objet",
callback: () => { callback: () => {
console.log("Delete : ", itemId); console.log("Delete : ", itemId);
actorSheet.actor.deleteOwnedItem(itemId); actorSheet.actor.deleteEmbeddedDocuments('Item', [itemId]);
li.slideUp(200, () => actorSheet.render(false)); li.slideUp(200, () => actorSheet.render(false));
} }
}, },
@ -671,8 +730,9 @@ export class RdDUtility {
label: "Annuler" label: "Annuler"
} }
} }
if (objet.data.type == 'conteneur' && objet.data.data.contenu.length > 0) { const docData = Misc.data(objet);
msgTxt += "<br>Cet objet est aussi un conteneur avec du contenu : choisissez l'option de suppression"; if (docData.type == 'conteneur' && docData.data.contenu.length > 0) {
msgTxt += "<br>Ce conteneur n'est pas vide. Choisissez l'option de suppression";
buttons['deleteall'] = { buttons['deleteall'] = {
icon: '<i class="fas fa-check"></i>', icon: '<i class="fas fa-check"></i>',
label: "Supprimer le conteneur et tout son contenu", label: "Supprimer le conteneur et tout son contenu",
@ -699,7 +759,7 @@ export class RdDUtility {
let ajustement = game.system.rdd.calendrier.getAjustementAstrologique(heureNaissance); let ajustement = game.system.rdd.calendrier.getAjustementAstrologique(heureNaissance);
ChatMessage.create({ ChatMessage.create({
content: `A l'heure ${game.system.rdd.calendrier.getCurrentHeure()}, le modificateur de Chance/Malchance pour l'heure de naissance ${heureNaissance} est de : ${ajustement}.`, content: `A l'heure ${game.system.rdd.calendrier.getCurrentHeure()}, le modificateur de Chance/Malchance pour l'heure de naissance ${heureNaissance} est de : ${ajustement}.`,
whisper: ChatMessage.getWhisperRecipients("MJ") whisper: ChatMessage.getWhisperRecipients("GM")
}); });
} }
else { else {

View File

@ -1,12 +1,15 @@
import { Misc } from "./misc.js";
const listeReglesOptionelles = [ const listeReglesOptionelles = [
{name:'recul', group:'combat', descr:"Appliquer le recul en cas de particulière en force ou de charge"}, { name: 'recul', group: 'Règles de combat', descr: "Appliquer le recul en cas de particulière en force ou de charge" },
{name:'resistanceArmeParade', group:'combat', descr:"Faire le jet de résistance des armes lors de parades pouvant les endommager"}, { name: 'resistanceArmeParade', group: 'Règles de combat', descr: "Faire le jet de résistance des armes lors de parades pouvant les endommager" },
{name:'deteriorationArmure', group:'combat', descr:"Tenir compte de la détérioration des armures"}, { name: 'deteriorationArmure', group: 'Règles de combat', descr: "Tenir compte de la détérioration des armures" },
{name:'defenseurDesarme', group:'combat', 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"}, { name: 'defenseurDesarme', group: 'Règles de combat', 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" },
{name:'categorieParade', group:'combat', descr:"Le défenseur doit obtenir une significative en cas de parade avec des armes de catégories différentes"}, { name: 'categorieParade', group: 'Règles de combat', descr: "Le défenseur doit obtenir une significative en cas de parade avec des armes de catégories différentes" },
{name:'tripleSignificative', group:'combat', descr:"En cas de demi-surprise, d'attaque particulière en finesse, et de catégories d'armes différentes, le défenseur doit obtenir 1/8 des chances de succès"}, { name: 'tripleSignificative', group: 'Règles de combat', descr: "En cas de demi-surprise, d'attaque particulière en finesse, et de catégories d'armes différentes, le défenseur doit obtenir 1/8 des chances de succès" },
{name:'astrologie', group:'generale', descr:"Appliquer les ajustements astrologiques aux jets de chance et aux rituels"} { name: 'astrologie', group: 'Règles de générales', descr: "Appliquer les ajustements astrologiques aux jets de chance et aux rituels", default: true },
{ name: 'afficher-prix-joueurs', group: 'Règles de générales', descr: "Afficher le prix de l'équipement des joueurs", default: true },
{ name: 'appliquer-fatigue', group: 'Règles de générales', descr: "Appliquer les règles de fatigue", default: true },
]; ];
export class ReglesOptionelles extends FormApplication { export class ReglesOptionelles extends FormApplication {
@ -14,7 +17,7 @@ export class ReglesOptionelles extends FormApplication {
for (const regle of listeReglesOptionelles) { for (const regle of listeReglesOptionelles) {
const name = regle.name; const name = regle.name;
const id = ReglesOptionelles._getIdRegle(name); const id = ReglesOptionelles._getIdRegle(name);
game.settings.register("foundryvtt-reve-de-dragon", id, { name: id, scope: "world", config: false, default: regle.default??true, type: Boolean }); game.settings.register("foundryvtt-reve-de-dragon", id, { name: id, scope: "world", config: false, default: regle.default == undefined ? true : regle.default, type: Boolean });
} }
game.settings.registerMenu("foundryvtt-reve-de-dragon", "rdd-options-regles", { game.settings.registerMenu("foundryvtt-reve-de-dragon", "rdd-options-regles", {
@ -38,25 +41,27 @@ export class ReglesOptionelles extends FormApplication {
static get defaultOptions() { static get defaultOptions() {
const options = super.defaultOptions; const options = super.defaultOptions;
mergeObject(options, { mergeObject(options, {
id: "combat-settings", id: "optional-settings",
template: "systems/foundryvtt-reve-de-dragon/templates/regles-optionelles.html", template: "systems/foundryvtt-reve-de-dragon/templates/regles-optionelles.html",
height: 600, height: 600,
width: 350, width: 350,
minimizable: false, minimizable: false,
closeOnSubmit: true, closeOnSubmit: true,
title: "Options de combat" title: "Règles optionnelles"
}); });
return options; return options;
} }
getData() { getData() {
let formData = super.getData(); let formData = super.getData();
formData.regles = listeReglesOptionelles.map(it => { const regles = listeReglesOptionelles.map(it => {
let r = duplicate(it); it = duplicate(it);
r.id = ReglesOptionelles._getIdRegle(r.name); it.id = ReglesOptionelles._getIdRegle(it.name);
r.active = ReglesOptionelles.isUsing(r.name); it.active = ReglesOptionelles.isUsing(it.name);
return r; return it;
}) });
formData.regles = regles;
formData.groups = Misc.classify(regles, it => it.group);
return formData; return formData;
} }

View File

@ -55,7 +55,7 @@ export const referenceAjustements = {
getValue: (rollData, actor) => actor.getEtatGeneral() getValue: (rollData, actor) => actor.getEtatGeneral()
}, },
malusArmure: { malusArmure: {
isVisible: (rollData, actor) => RdDCarac.isAgiliteOuDerivee(rollData.competence), isVisible: (rollData, actor) => RdDCarac.isAgiliteOuDerivee(rollData.selectedCarac),
isUsed: (rollData, actor) => RdDCarac.isAgiliteOuDerivee(rollData.selectedCarac), isUsed: (rollData, actor) => RdDCarac.isAgiliteOuDerivee(rollData.selectedCarac),
getLabel: (rollData, actor) => 'Malus armure', getLabel: (rollData, actor) => 'Malus armure',
getValue: (rollData, actor) => actor.getMalusArmure() getValue: (rollData, actor) => actor.getMalusArmure()
@ -131,6 +131,7 @@ export class RollDataAjustements {
for (var key in referenceAjustements) { for (var key in referenceAjustements) {
const reference = referenceAjustements[key]; const reference = referenceAjustements[key];
rollData.ajustements[key] = { rollData.ajustements[key] = {
visible: reference.isVisible && reference.isVisible(rollData, actor),
used: reference.isUsed(rollData, actor), used: reference.isUsed(rollData, actor),
label: reference.getLabel && reference.getLabel(rollData, actor), label: reference.getLabel && reference.getLabel(rollData, actor),
value: reference.getValue && reference.getValue(rollData, actor), value: reference.getValue && reference.getValue(rollData, actor),

View File

@ -1,6 +1,6 @@
import { DeDraconique } from "./de-draconique.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
import { TMRUtility } from "./tmr-utility.js"; import { TMRUtility } from "./tmr-utility.js";
import { TMRType } from "./tmr-utility.js"; import { TMRType } from "./tmr-utility.js";
@ -8,11 +8,11 @@ import { TMRType } from "./tmr-utility.js";
const typeRencontres = { const typeRencontres = {
messager: { messager: {
msgSucces: (data) => `Le ${data.rencontre.name} vous propose d'emmener le message de votre un sort à ${data.rencontre.force} cases ${data.tmr.label}.`, msgSucces: (rencData) => `Le ${rencData.rencontre.name} vous propose d'emmener le message de votre un sort à ${rencData.rencontre.force} cases ${rencData.tmr.label}.`,
msgEchec: (data) => `Le ${data.rencontre.name} est pressé et continue son chemin d'une traite sans vous accorder un regard.`, msgEchec: (rencData) => `Le ${rencData.rencontre.name} est pressé et continue son chemin d'une traite sans vous accorder un regard.`,
postSucces: (tmrDialog, data) => { postSucces: (tmrDialog, rencData) => {
tmrDialog.setStateRencontre(data.rencontre.type); tmrDialog.setStateRencontre(rencData.rencontre.type);
tmrDialog.choisirCasePortee(data.tmr.coord, data.rencontre.force); tmrDialog.choisirCasePortee(rencData.tmr.coord, rencData.rencontre.force);
}, },
poesieSucces: { poesieSucces: {
reference: "La chevelure, Charles Baudelaire", reference: "La chevelure, Charles Baudelaire",
@ -28,11 +28,11 @@ const typeRencontres = {
}, },
passeur: { passeur: {
msgSucces: (data) => `Le ${data.rencontre.name} vous propose de vous transporter à ${data.rencontre.force} cases des ${data.tmr.label}.`, msgSucces: (rencData) => `Le ${rencData.rencontre.name} vous propose de vous transporter à ${rencData.rencontre.force} cases des ${rencData.tmr.label}.`,
msgEchec: (data) => `Le prix que demande le ${data.rencontre.name} est trop élevé, vous êtes réduit à poursuivre votre chemin par vos propres moyens.`, msgEchec: (rencData) => `Le prix que demande le ${rencData.rencontre.name} est trop élevé, vous êtes réduit à poursuivre votre chemin par vos propres moyens.`,
postSucces: (tmrDialog, data) => { postSucces: (tmrDialog, rencData) => {
tmrDialog.setStateRencontre(data.rencontre.type); tmrDialog.setStateRencontre(rencData.rencontre.type);
tmrDialog.choisirCasePortee(data.tmr.coord, data.rencontre.force); tmrDialog.choisirCasePortee(rencData.tmr.coord, rencData.rencontre.force);
}, },
poesieSucces: { poesieSucces: {
reference: "Femmes damnées (2), Charles Baudelaire", reference: "Femmes damnées (2), Charles Baudelaire",
@ -49,9 +49,9 @@ const typeRencontres = {
}, },
fleur: { fleur: {
msgSucces: (data) => `Vous cueillez la ${data.rencontre.name}, son parfum vous apporte ${data.rencontre.force} points de Rêve.`, msgSucces: (rencData) => `Vous cueillez la ${rencData.rencontre.name}, son parfum vous apporte ${rencData.rencontre.force} points de Rêve.`,
msgEchec: (data) => `La ${data.rencontre.name} se fâne et disparaît entre vos doigts.`, msgEchec: (rencData) => `La ${rencData.rencontre.name} se fâne et disparaît entre vos doigts.`,
postSucces: (tmrDialog, data) => tmrDialog.actor.reveActuelIncDec(data.rencontre.force), postSucces: (tmrDialog, rencData) => tmrDialog.actor.reveActuelIncDec(rencData.rencontre.force),
poesieSucces: { poesieSucces: {
reference: "L'Ennemi, Charles Baudelaire", reference: "L'Ennemi, Charles Baudelaire",
extrait: `Et qui sait si les fleurs nouvelles que je rêve extrait: `Et qui sait si les fleurs nouvelles que je rêve
@ -66,9 +66,9 @@ const typeRencontres = {
}, },
mangeur: { mangeur: {
msgSucces: (data) => `Le ${data.rencontre.name} claque de sa machoire dans le vide avant de fuir.`, msgSucces: (rencData) => `Le ${rencData.rencontre.name} claque de sa machoire dans le vide avant de fuir.`,
msgEchec: (data) => `Le ${data.rencontre.name} croque votre Rêve ! Il emporte ${data.rencontre.force} de vos points de rêve actuels`, msgEchec: (rencData) => `Le ${rencData.rencontre.name} croque votre Rêve ! Il emporte ${rencData.rencontre.force} de vos points de rêve actuels`,
postEchec: (tmrDialog, data) => tmrDialog.actor.reveActuelIncDec(-data.rencontre.force), postEchec: (tmrDialog, rencData) => tmrDialog.actor.reveActuelIncDec(-rencData.rencontre.force),
poesieSucces: { poesieSucces: {
reference: "Conseil, Victor Hugo", reference: "Conseil, Victor Hugo",
extrait: `Rois ! la bure est souvent jalouse du velours. extrait: `Rois ! la bure est souvent jalouse du velours.
@ -85,16 +85,16 @@ const typeRencontres = {
}, },
changeur: { changeur: {
msgSucces: (data) => `Le ${data.rencontre.name} vaincu accepte de vous déplacer sur une autre ${TMRType[data.tmr.type].name} de votre choix en échange de sa liberté.`, msgSucces: (rencData) => `Le ${rencData.rencontre.name} vaincu accepte de vous déplacer sur une autre ${TMRType[rencData.tmr.type].name} de votre choix en échange de sa liberté.`,
msgEchec: (data) => { msgEchec: (rencData) => {
data.newTMR = TMRUtility.getTMRAleatoire(it => it.type = data.tmr.type); rencData.newTMR = TMRUtility.getTMRAleatoire(it => it.type = rencData.tmr.type);
return `Le ${data.rencontre.name} vous embobine avec des promesses, et vous transporte en ${data.newTMR.label} sans attendre votre avis.`; return `Le ${rencData.rencontre.name} vous embobine avec des promesses, et vous transporte en ${rencData.newTMR.label} sans attendre votre avis.`;
}, },
postSucces: (tmrDialog, data) => { postSucces: (tmrDialog, rencData) => {
tmrDialog.setStateRencontre(data.rencontre.type); tmrDialog.setStateRencontre(rencData.rencontre.type);
tmrDialog.choisirCaseType(data.tmr.type); tmrDialog.choisirCaseType(rencData.tmr.type);
}, },
postEchec: (tmrDialog, data) => tmrDialog.forceDemiRevePosition(data.newTMR.coord), postEchec: (tmrDialog, rencData) => tmrDialog.forceDemiRevePosition(rencData.newTMR.coord),
poesieSucces: { poesieSucces: {
reference: "Caligula - IIIème chant, Gérard de Nerval", reference: "Caligula - IIIème chant, Gérard de Nerval",
extrait: `Allez, que le caprice emporte extrait: `Allez, que le caprice emporte
@ -111,9 +111,9 @@ const typeRencontres = {
}, },
briseur: { briseur: {
msgSucces: (data) => `Le ${data.rencontre.name} tente vainement de vous déconcentrer, avant de fuir sans demander son reste.`, msgSucces: (rencData) => `Le ${rencData.rencontre.name} tente vainement de vous déconcentrer, avant de fuir sans demander son reste.`,
msgEchec: (data) => `Le ${data.rencontre.name} vous déconcentre au point de briser votre demi-rêve.`, msgEchec: (rencData) => `Le ${rencData.rencontre.name} vous déconcentre au point de briser votre demi-rêve.`,
postEchec: (tmrDialog, data) => tmrDialog.close(), postEchec: (tmrDialog, rencData) => tmrDialog.close(),
poesieSucces: { poesieSucces: {
reference: "Rêve de Dragon, Denis Gerfaud", reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `La légende affirme que ce sont les Gnomes qui furent extrait: `La légende affirme que ce sont les Gnomes qui furent
@ -134,8 +134,8 @@ const typeRencontres = {
}, },
reflet: { reflet: {
msgSucces: (data) => `Le ${data.rencontre.name} s'estompe dans l'oubli.`, msgSucces: (rencData) => `Le ${rencData.rencontre.name} s'estompe dans l'oubli.`,
msgEchec: (data) => `Vous êtes submergé par un ${data.rencontre.name}, les souvenirs vous retiennent tant qu'il ne sera pas vaincu!`, msgEchec: (rencData) => `Vous êtes submergé par un ${rencData.rencontre.name}, les souvenirs vous retiennent tant qu'il ne sera pas vaincu!`,
poesieSucces: { poesieSucces: {
reference: "Une charogne, Charles Baudelaire", reference: "Une charogne, Charles Baudelaire",
extrait: `Les formes s'effaçaient et n'étaient plus qu'un rêve, extrait: `Les formes s'effaçaient et n'étaient plus qu'un rêve,
@ -152,9 +152,9 @@ const typeRencontres = {
}, },
passeurfou: { passeurfou: {
msgSucces: (data) => `Le ${data.rencontre.name} tente vainement de découvrir où vous avez caché vos réserves. Vous le chassez, et en déroute il part harceler un autre voyageur du rêve.`, msgSucces: (rencData) => `Le ${rencData.rencontre.name} tente vainement de découvrir où vous avez caché vos réserves. Vous le chassez, et en déroute il part harceler un autre voyageur du rêve.`,
msgEchec: (data) => TMRRencontres.msgEchecPasseurFou(data), msgEchec: (rencData) => TMRRencontres.msgEchecPasseurFou(rencData),
postEchec: (tmrDialog, data) => TMRRencontres.postEchecPasseurFou(tmrDialog, data), postEchec: (tmrDialog, rencData) => TMRRencontres.postEchecPasseurFou(tmrDialog, rencData),
poesieSucces: { poesieSucces: {
reference: "Un Fou et un Sage, Jean de La Fontaine", reference: "Un Fou et un Sage, Jean de La Fontaine",
extrait: `Certain Fou poursuivait à coups de pierre un Sage. extrait: `Certain Fou poursuivait à coups de pierre un Sage.
@ -174,9 +174,9 @@ const typeRencontres = {
}, },
tbblanc: { tbblanc: {
msgSucces: (data) => `Le ${data.rencontre.name} souleve une poussière blanche, vous tenez bon, et il tourbillonne en s'éloignant.`, msgSucces: (rencData) => `Le ${rencData.rencontre.name} souleve une poussière blanche, vous tenez bon, et il tourbillonne en s'éloignant.`,
msgEchec: (data) => `Le souffle du ${data.rencontre.name} vous déstabilise et vous emmène dans un nuage de poussière.`, msgEchec: (rencData) => `Le souffle du ${rencData.rencontre.name} vous déstabilise et vous emmène dans un nuage de poussière.`,
postEchec: (tmrDialog, data) => TMRRencontres.onPostEchecTourbillon(tmrDialog, data, 1), postEchec: (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillon(tmrDialog, rencData, 1),
poesieSucces: { poesieSucces: {
reference: "Rêve de Dragon, Denis Gerfaud", reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `Le Premier Âge fut appelé l'Âge des Dragons. Ce fut le commencement extrait: `Le Premier Âge fut appelé l'Âge des Dragons. Ce fut le commencement
@ -191,9 +191,9 @@ const typeRencontres = {
}, },
tbnoir: { tbnoir: {
msgSucces: (data) => `Le ${data.rencontre.name} orageux vous enveloppe de fureur et d'éclairs, vous tenez bon face à la tempête qui s'éloigne sans vous éloigner de votre chemin.`, msgSucces: (rencData) => `Le ${rencData.rencontre.name} orageux vous enveloppe de fureur et d'éclairs, vous tenez bon face à la tempête qui s'éloigne sans vous éloigner de votre chemin.`,
msgEchec: (data) => `Le ${data.rencontre.name} furieux vous secoue tel un fichu de paille malmené par les vents, et vous emporte dans la tourmente.`, msgEchec: (rencData) => `Le ${rencData.rencontre.name} furieux vous secoue tel un fichu de paille malmené par les vents, et vous emporte dans la tourmente.`,
postEchec: (tmrDialog, data) => TMRRencontres.onPostEchecTourbillon(tmrDialog, data, 2), postEchec: (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillon(tmrDialog, rencData, 2),
poesieSucces: { poesieSucces: {
reference: "Rêve de Dragon, Denis Gerfaud", reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `Car le Second Âge fut bel et bien celui des Magiciens. Durant cette période, les extrait: `Car le Second Âge fut bel et bien celui des Magiciens. Durant cette période, les
@ -207,9 +207,9 @@ const typeRencontres = {
}, },
tbrouge: { tbrouge: {
msgSucces: (data) => `Le ${data.rencontre.name} s'abat avec violence mais vous êtes plus rapide et parvenez à lui échapper.`, msgSucces: (rencData) => `Le ${rencData.rencontre.name} s'abat avec violence mais vous êtes plus rapide et parvenez à lui échapper.`,
msgEchec: (data) => `Le ${data.rencontre.name} vous frappe de milliers de morsure et vous malmène à travers les terres médianes.`, msgEchec: (rencData) => `Le ${rencData.rencontre.name} vous frappe de milliers de morsure et vous malmène à travers les terres médianes.`,
postEchec: (tmrDialog, data) => TMRRencontres.onPostEchecTourbillonRouge(tmrDialog, data), postEchec: (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillonRouge(tmrDialog, rencData),
poesieSucces: { poesieSucces: {
reference: "Qu'est-ce de votre vie ? une bouteille molle, Jean-Baptiste Chassignet", reference: "Qu'est-ce de votre vie ? une bouteille molle, Jean-Baptiste Chassignet",
extrait: `Qu'est-ce de votre vie ? un tourbillon rouant extrait: `Qu'est-ce de votre vie ? un tourbillon rouant
@ -228,10 +228,10 @@ const typeRencontres = {
}, },
rdd: { rdd: {
msgSucces: (data) => `A tout seigneur, tout honneur, vous faites face à un ${data.rencontre.name}. Vous le maîtrisez et récupérez ses rêves. Vous gagnez ses ${data.rencontre.force} points de rêve`, msgSucces: (rencData) => `A tout seigneur, tout honneur, vous faites face à un ${rencData.rencontre.name}. Vous le maîtrisez et récupérez ses rêves. Vous gagnez ses ${rencData.rencontre.force} points de rêve`,
msgEchec: (data) => `A tout seigneur, tout honneur, vous faites face à un ${data.rencontre.name}. La rencontre tourne au cauchemar, dans la lutte épique, vous subissez ${data.rolled.isETotal ? 'deux queues' : 'une queue'} de dragon!`, msgEchec: (rencData) => `A tout seigneur, tout honneur, vous faites face à un ${rencData.rencontre.name}. La rencontre tourne au cauchemar, dans la lutte épique, vous subissez ${rencData.rolled.isETotal ? 'deux queues' : 'une queue'} de dragon!`,
postSucces: (tmrDialog, data) => TMRRencontres.onPostSuccessReveDeDragon(tmrDialog, data), postSucces: (tmrDialog, rencData) => TMRRencontres.onPostSuccessReveDeDragon(tmrDialog, rencData),
postEchec: (tmrDialog, data) => TMRRencontres.onPostEchecReveDeDragon(tmrDialog, data), postEchec: (tmrDialog, rencData) => TMRRencontres.onPostEchecReveDeDragon(tmrDialog, rencData),
poesieSucces: { poesieSucces: {
reference: "Rêve de Dragon, Denis Gerfaud", reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `Le monde est Rêve de Dragons, mais nous ne savons extrait: `Le monde est Rêve de Dragons, mais nous ne savons
@ -269,7 +269,7 @@ const rencontresStandard = [
{ code: "reflet", name: "Reflet d'ancien Rêve", type: "reflet", genre: "m", force: "2d6", isPersistant: true }, { code: "reflet", name: "Reflet d'ancien Rêve", type: "reflet", genre: "m", force: "2d6", isPersistant: true },
{ code: "tbblanc", name: "Tourbillon blanc", type: "tbblanc", genre: "m", force: "2d6", isPersistant: true }, { code: "tbblanc", name: "Tourbillon blanc", type: "tbblanc", genre: "m", force: "2d6", isPersistant: true },
{ code: "tbnoir", name: "Tourbillon noir", type: "tbnoir", genre: "m", force: "2d8", isPersistant: true }, { code: "tbnoir", name: "Tourbillon noir", type: "tbnoir", genre: "m", force: "2d8", isPersistant: true },
{ code: "rdd", name: "Rêve de Dragon", type: "rdd", genre: "m", force: "1ddr + 7", refoulement: 2, quitterTMR: true } { code: "rdd", name: "Rêve de Dragon", type: "rdd", genre: "m", force: "1dr + 7", refoulement: 2, quitterTMR: true }
]; ];
const rencontresPresentCite = [ const rencontresPresentCite = [
@ -325,12 +325,12 @@ export class TMRRencontres {
return false; return false;
} }
if (!roll || roll <= 0 || roll > 100) { if (!roll || roll <= 0 || roll > 100) {
roll = new Roll("1d100").evaluate().total; roll = await RdDDice.rollTotal("1d100");
} }
let rencontre = await TMRRencontres.getRencontreAleatoire(terrain, roll); let rencontre = await TMRRencontres.getRencontreAleatoire(terrain, roll);
ChatMessage.create({ ChatMessage.create({
user: game.user._id, user: game.user.id,
whisper: [game.user._id], whisper: [game.user.id],
content: `Rencontre en ${terrain} (jet : ${roll}%)<br>Vous rencontrez un ${rencontre.name} de ${rencontre.force} Points de Rêve` content: `Rencontre en ${terrain} (jet : ${roll}%)<br>Vous rencontrez un ${rencontre.name} de ${rencontre.force} Points de Rêve`
}); });
return false; return false;
@ -349,7 +349,7 @@ export class TMRRencontres {
return duplicate(rencontre); return duplicate(rencontre);
} }
else { else {
ui.notifications.info(`Pas de rencontre pour ${index}, seulement ${rencontresAll.length} rencontres sont connues.<br>Vous pouvez aussi essayer par type (ie: mangeur, fleur, fleur2d6, ...)`) ui.notifications.info(`Pas de rencontre pour ${index}, seulement ${rencontresAll.length} rencontres sont connues.<br>Vous pouvez aussi essayer par type (ie: mangeur, fleur, fleur2d6, ...)`)
} }
return undefined; return undefined;
} }
@ -357,15 +357,13 @@ export class TMRRencontres {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async getRencontreAleatoire(terrain, roll = undefined) { static async getRencontreAleatoire(terrain, roll = undefined) {
if (!roll || roll <= 0 || roll > 100) { if (!roll || roll <= 0 || roll > 100) {
roll = new Roll("1d100").evaluate().total; roll = await RdDDice.rollTotal("1d100");
} }
terrain = Grammar.toLowerCaseNoAccent(terrain); terrain = Grammar.toLowerCaseNoAccent(terrain);
//console.log("getRencontreAleatoire", terrain, roll);
const code = tableRencontres[terrain].find(it => it.range[0] <= roll && roll <= it.range[1]).code; const code = tableRencontres[terrain].find(it => it.range[0] <= roll && roll <= it.range[1]).code;
const rencontre = duplicate(rencontresStandard.find(it => it.code == code)); const rencontre = duplicate(rencontresStandard.find(it => it.code == code));
rencontre.roll = roll; rencontre.roll = roll;
await TMRRencontres.evaluerForceRencontre(rencontre); await TMRRencontres.evaluerForceRencontre(rencontre);
//console.log(rencontre);
return rencontre; return rencontre;
} }
@ -374,20 +372,14 @@ export class TMRRencontres {
const rencontre = duplicate( const rencontre = duplicate(
(index && index >= 0 && index < mauvaisesRencontres.length) (index && index >= 0 && index < mauvaisesRencontres.length)
? mauvaisesRencontres[index] ? mauvaisesRencontres[index]
: Misc.rollOneOf(mauvaisesRencontres)); : await RdDDice.rollOneOf(mauvaisesRencontres));
await TMRRencontres.evaluerForceRencontre(rencontre); await TMRRencontres.evaluerForceRencontre(rencontre);
return rencontre; return rencontre;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async evaluerForceRencontre(rencontre) { static async evaluerForceRencontre(rencontre) {
if (TMRRencontres.isReveDeDragon(rencontre)) { rencontre.force = await new Roll(rencontre.force).evaluate().total;
const ddr = await DeDraconique.ddr("selfroll")
rencontre.force = 7 + ddr.total;
}
else {
rencontre.force = new Roll(rencontre.force).evaluate().total;
}
return rencontre.force; return rencontre.force;
} }
@ -407,58 +399,59 @@ export class TMRRencontres {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async gererRencontre(tmrDialog, data) { static async gererRencontre(tmrDialog, rencData) {
let gestion = TMRRencontres.getGestionRencontre(data.rencontre.type); let gestion = TMRRencontres.getGestionRencontre(rencData.rencontre.type);
if (data.rolled.isSuccess) { if (rencData.rolled.isSuccess) {
data.message = gestion.msgSucces(data); rencData.message = gestion.msgSucces(rencData);
if (data.nbRounds > 1) { if (rencData.nbRounds > 1) {
data.message += ` Au total, vous avez passé ${data.nbRounds} rounds à vous battre!`; rencData.message += ` Au total, vous avez passé ${rencData.nbRounds} rounds à vous battre!`;
} }
data.poesie = gestion.poesieSucces; rencData.poesie = gestion.poesieSucces;
return gestion.postSucces; return gestion.postSucces;
} }
data.message = gestion.msgEchec(data); rencData.message = gestion.msgEchec(rencData);
if (data.nbRounds > 1) { if (rencData.nbRounds > 1) {
data.message += ` Vous avez passé ${data.nbRounds} rounds à lutter!`; rencData.message += ` Vous avez passé ${rencData.nbRounds} rounds à lutter!`;
} }
data.poesie = gestion.poesieEchec; rencData.poesie = gestion.poesieEchec;
return gestion.postEchec; return gestion.postEchec;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static msgEchecPasseurFou(data) { static async msgEchecPasseurFou(tmrData) {
data.sortReserve = data.actor.data.data.reve.reserve.list[0]; tmrData.sortReserve = Misc.templateData(tmrData.actor).reve.reserve.list[0];
if (data.sortReserve) { if (tmrData.sortReserve) {
// Passeur fou positionne sur la case d'un ort en réserve // TODO : Choisir le sort le plus loin ou au hasard // Passeur fou positionne sur la case d'un ort en réserve // TODO : Choisir le sort le plus loin ou au hasard
data.newTMR = TMRUtility.getTMR(data.sortReserve.coord); tmrData.newTMR = TMRUtility.getTMR(tmrData.sortReserve.coord);
} else { } else {
// Déplacement aléatoire de la force du Passeur Fou // Déplacement aléatoire de la force du Passeur Fou
const newCoord = Misc.rollOneOf(TMRUtility.getTMRPortee(data.tmr.coord, data.rencontre.force)); const newCoord = await RdDDice.rollOneOf(TMRUtility.getTMRPortee(tmrData.tmr.coord, tmrData.rencontre.force));
data.newTMR = TMRUtility.getTMR(newCoord); tmrData.newTMR = TMRUtility.getTMR(newCoord);
} }
if (data.sortReserve) { if (tmrData.sortReserve) {
return `Le ${data.rencontre.name} vous dérobe la clé de vos sorts. Vous vous saisissez de lui, mais dans un nuage violet, il vous emporte en ${data.newTMR.label} déclencher votre sort en réserve de ${data.sortReserve.name}.`; return `Le ${tmrData.rencontre.name} vous dérobe la clé de vos sorts. Vous vous saisissez de lui, mais dans un nuage violet, il vous emporte en ${tmrData.newTMR.label} déclencher votre sort en réserve de ${tmrData.sortReserve.name}.`;
} }
else { else {
return `Le ${data.rencontre.name} tente de vous dérober la clé de vos sorts. Ne la trouvant pas, il déclenche un nuage violet et vous emporte en ${data.newTMR.label}`; return `Le ${tmrData.rencontre.name} tente de vous dérober la clé de vos sorts. Ne la trouvant pas, il déclenche un nuage violet et vous emporte en ${tmrData.newTMR.label}`;
} }
} }
static async postEchecPasseurFou(tmrDialog, data) { /* -------------------------------------------- */
if (data.sortReserve) { static async postEchecPasseurFou(tmrDialog, tmrData) {
await tmrDialog.processSortReserve(data.sortReserve); if (tmrData.sortReserve) {
await tmrDialog.processSortReserve(tmrData.sortReserve);
} }
await tmrDialog.forceDemiRevePosition(data.newTMR.coord); await tmrDialog.forceDemiRevePosition(tmrData.newTMR.coord);
if (data.sortReserve) { if (tmrData.sortReserve) {
tmrDialog.close(); tmrDialog.close();
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async onPostEchecTourbillon(tmrDialog, data, cases) { static async onPostEchecTourbillon(tmrDialog, tmrData, cases) {
await data.actor.reveActuelIncDec(-cases); await tmrData.actor.reveActuelIncDec(-cases);
await TMRRencontres._toubillonner(tmrDialog, data.actor, cases); await TMRRencontres._toubillonner(tmrDialog, tmrData.actor, cases);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -468,23 +461,26 @@ export class TMRRencontres {
await data.actor.santeIncDec("vie", -1); // Et -1 PV await data.actor.santeIncDec("vie", -1); // Et -1 PV
} }
/* -------------------------------------------- */
static async _toubillonner(tmrDialog, actor, cases) { static async _toubillonner(tmrDialog, actor, cases) {
let coord = actor.data.data.reve.tmrpos.coord; let coord = Misc.templateData(actor).reve.tmrpos.coord;
for (let i = 0; i < cases; i++) { for (let i = 0; i < cases; i++) {
coord = TMRUtility.deplaceTMRAleatoire(actor, coord).coord; coord = await TMRUtility.deplaceTMRAleatoire(actor, coord).coord;
} }
await tmrDialog.forceDemiRevePosition(coord) await tmrDialog.forceDemiRevePosition(coord)
} }
static async onPostSuccessReveDeDragon(tmrDialog, data) { /* -------------------------------------------- */
if (data.rolled.isPart) { static async onPostSuccessReveDeDragon(tmrDialog, tmrData) {
await data.actor.appliquerExperience(data.rolled, 'reve', data.competence); if (tmrData.rolled.isPart) {
await tmrData.actor.appliquerExperience(tmrData.rolled, 'reve', tmrData.competence);
} }
await data.actor.resultCombatReveDeDragon(data); await tmrData.actor.resultCombatReveDeDragon(tmrData);
} }
static async onPostEchecReveDeDragon(tmrDialog, data) { /* -------------------------------------------- */
await data.actor.resultCombatReveDeDragon(data); static async onPostEchecReveDeDragon(tmrDialog, tmrData) {
await tmrData.actor.resultCombatReveDeDragon(tmrData);
tmrDialog.close(); tmrDialog.close();
} }
} }

View File

@ -1,5 +1,7 @@
import { TMRRencontres } from "./tmr-rencontres.js"; import { TMRRencontres } from "./tmr-rencontres.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { Grammar } from "./grammar.js";
import { RdDDice } from "./rdd-dice.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
const TMRMapping = { const TMRMapping = {
@ -335,9 +337,20 @@ export class TMRUtility {
return TMRMapping[coord]?.label ?? (coord + ": case inconnue"); return TMRMapping[coord]?.label ?? (coord + ": case inconnue");
} }
static getTMRType(coord) {
const tmr = TMRMapping[coord];
return Misc.upperFirst(TMRType[tmr.type].name);
}
static getTMRDescr(coord) { static getTMRDescr(coord) {
const tmr = TMRMapping[coord]; const tmr = TMRMapping[coord];
return Grammar.articleDetermine(tmr.genre) + ' ' + tmr.label; return Grammar.articleDetermine(tmr.type) + ' ' + tmr.label;
}
static listSelectedTMR(typesTMR) {
return Object.values(TMRType).map(value => Misc.upperFirst(value.name))
.sort()
.map(name => { return { name: name, selected: typesTMR.includes(name) } });
} }
static isCaseHumide(tmr) { static isCaseHumide(tmr) {
@ -374,12 +387,13 @@ export class TMRUtility {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getDirectionPattern() { static async getDirectionPattern() {
return Misc.rollOneOf(tmrRandomMovePatten); return await RdDDice.rollOneOf(tmrRandomMovePatten);
} }
static deplaceTMRAleatoire(actor, coord) { /* -------------------------------------------- */
return TMRUtility.deplaceTMRSelonPattern(actor, coord, TMRUtility.getDirectionPattern(), 1); static async deplaceTMRAleatoire(actor, coord) {
return TMRUtility.deplaceTMRSelonPattern(actor, coord, await TMRUtility.getDirectionPattern(), 1);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -411,8 +425,8 @@ export class TMRUtility {
return TMRUtility.filterTMR(filter).map(it => it.coord); return TMRUtility.filterTMR(filter).map(it => it.coord);
} }
static getTMRAleatoire(filter = it => true) { static async getTMRAleatoire(filter = it => true) {
return Misc.rollOneOf(TMRUtility.filterTMR(filter)) return await RdDDice.rollOneOf(TMRUtility.filterTMR(filter))
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -465,12 +479,14 @@ export class TMRUtility {
return caseList; return caseList;
} }
/* -------------------------------------------- */
static distanceTMR(coord1, coord2) { static distanceTMR(coord1, coord2) {
let pos1 = this.convertToCellPos(coord1); let pos1 = this.convertToCellPos(coord1);
let pos2 = this.convertToCellPos(coord2); let pos2 = this.convertToCellPos(coord2);
return this.distancePosTMR(pos1, pos2); return this.distancePosTMR(pos1, pos2);
} }
/* -------------------------------------------- */
static distancePosTMR(pos1, pos2) { static distancePosTMR(pos1, pos2) {
const dx = pos2.x - pos1.x; const dx = pos2.x - pos1.x;
const dy = pos2.y - pos1.y; const dy = pos2.y - pos1.y;

View File

@ -1,5 +1,6 @@
import { Grammar } from "../grammar.js"; import { Grammar } from "../grammar.js";
import { Misc } from "../misc.js"; import { Misc } from "../misc.js";
import { RdDDice } from "../rdd-dice.js";
import { tmrColors, tmrConstants, tmrTokenZIndex, TMRUtility } from "../tmr-utility.js"; import { tmrColors, tmrConstants, tmrTokenZIndex, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js"; import { Draconique } from "./draconique.js";
@ -15,7 +16,7 @@ export class Conquete extends Draconique {
async onActorCreateOwned(actor, item) { await this._creerConquete(actor, item); } async onActorCreateOwned(actor, item) { await this._creerConquete(actor, item); }
code() { return 'conquete' } code() { return 'conquete' }
tooltip(linkData) { return `La ${this.tmrLabel(linkData)} doit être conquise` } tooltip(linkData) { return `${this.tmrLabel(linkData)}: doit être conquis` }
img() { return 'icons/svg/combat.svg' } img() { return 'icons/svg/combat.svg' }
createSprite(pixiTMR) { createSprite(pixiTMR) {
@ -29,14 +30,14 @@ export class Conquete extends Draconique {
} }
async _creerConquete(actor, queue) { async _creerConquete(actor, queue) {
let existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord); let existants = actor.data.items.filter(it => this.isCase(it)).map(it => Misc.data(it).data.coord);
let possibles = TMRUtility.filterTMR(tmr => !TMRUtility.isCaseHumide(tmr) && !existants.includes(tmr.coord)); let possibles = TMRUtility.filterTMR(tmr => !TMRUtility.isCaseHumide(tmr) && !existants.includes(tmr.coord));
let conquete = Misc.rollOneOf(possibles); let conquete =await RdDDice.rollOneOf(possibles);
await this.createCaseTmr(actor, 'Conquête: ' + conquete.label, conquete, queue._id); await this.createCaseTmr(actor, 'Conquête: ' + conquete.label, conquete, queue.id);
} }
async onActorDeleteCaseTmr(actor, casetmr) { async onActorDeleteCaseTmr(actor, casetmr) {
await actor.deleteOwnedItem(casetmr.data.sourceid); await actor.deleteEmbeddedDocuments('Item', [casetmr.data.sourceid]);
} }
} }

View File

@ -13,20 +13,20 @@ export class Debordement extends Draconique {
manualMessage() { return false } manualMessage() { return false }
async onActorCreateOwned(actor, souffle) { async onActorCreateOwned(actor, souffle) {
const existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord); const existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord);
const tmr = TMRUtility.getTMRAleatoire(it => !(TMRUtility.isCaseHumide(it) || existants.includes(it.coord))); const tmr = await TMRUtility.getTMRAleatoire(it => !(TMRUtility.isCaseHumide(it) || existants.includes(it.coord)));
await this.createCaseTmr(actor, 'Debordement: ' + tmr.label, tmr, souffle._id); await this.createCaseTmr(actor, 'Debordement: ' + tmr.label, tmr, souffle.id);
} }
code() { return 'debordement' } code() { return 'debordement' }
tooltip(linkData) { return `Débordement en ${this.tmrLabel(linkData)}` } tooltip(linkData) { return `Débordement en ${this.tmrLabel(linkData)}` }
img() { return 'systems/foundryvtt-reve-de-dragon/icons/tmr/wave.svg' } img() { return 'systems/foundryvtt-reve-de-dragon/icons/tmr/wave.webp' }
createSprite(pixiTMR) { createSprite(pixiTMR) {
return pixiTMR.sprite(this.code(), { return pixiTMR.sprite(this.code(), {
color: tmrColors.casehumide,
zIndex: tmrTokenZIndex.casehumide, zIndex: tmrTokenZIndex.casehumide,
taille: tmrConstants.twoThird, alpha: 0.6,
decallage: tmrConstants.bottom taille: tmrConstants.full,
decallage: tmrConstants.center
}); });
} }

View File

@ -1,5 +1,6 @@
import { Grammar } from "../grammar.js"; import { Grammar } from "../grammar.js";
import { Misc } from "../misc.js"; import { Misc } from "../misc.js";
import { RdDDice } from "../rdd-dice.js";
import { tmrColors, tmrConstants, tmrTokenZIndex, TMRType, TMRUtility } from "../tmr-utility.js"; import { tmrColors, tmrConstants, tmrTokenZIndex, TMRType, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js"; import { Draconique } from "./draconique.js";
@ -13,7 +14,7 @@ export class Desorientation extends Draconique {
manualMessage() { return false } manualMessage() { return false }
async onActorCreateOwned(actor, souffle) { async onActorCreateOwned(actor, souffle) {
const type = Misc.rollOneOf(this._typesPossibles(actor)); const type = await RdDDice.rollOneOf(this._typesPossibles(actor));
console.log("désorientation", type); console.log("désorientation", type);
souffle.name += ": " + TMRType[type].name; souffle.name += ": " + TMRType[type].name;
await this._creerCasesTmr(actor, type, souffle); await this._creerCasesTmr(actor, type, souffle);
@ -43,7 +44,7 @@ export class Desorientation extends Draconique {
const existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord); const existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord);
let tmrs = TMRUtility.filterTMR(it => it.type == type && !existants.includes(it.coord)); let tmrs = TMRUtility.filterTMR(it => it.type == type && !existants.includes(it.coord));
for (let tmr of tmrs) { for (let tmr of tmrs) {
await this.createCaseTmr(actor, 'Désorientation: ' + tmr.label, tmr, souffle._id); await this.createCaseTmr(actor, 'Désorientation: ' + tmr.label, tmr, souffle.id);
} }
} }

View File

@ -1,3 +1,4 @@
import { Misc } from "../misc.js";
import { TMRUtility } from "../tmr-utility.js"; import { TMRUtility } from "../tmr-utility.js";
import { PixiTMR } from "./pixi-tmr.js"; import { PixiTMR } from "./pixi-tmr.js";
@ -8,11 +9,11 @@ const registeredEffects = [
* Définition des informations d'une "draconique" (queue, ombre, tête, souffle) qui influence les TMR * Définition des informations d'une "draconique" (queue, ombre, tête, souffle) qui influence les TMR
*/ */
export class Draconique { export class Draconique {
static isCaseTMR(element) { return element.type == 'casetmr'; } static isCaseTMR(itemData) { return itemData.type == 'casetmr'; }
static isQueueDragon(element) { return element.type == 'queue' || element.type == 'ombre'; } static isQueueDragon(itemData) { return itemData.type == 'queue' || itemData.type == 'ombre'; }
static isSouffleDragon(element) { return element.type == 'souffle'; } static isSouffleDragon(itemData) { return itemData.type == 'souffle'; }
static isTeteDragon(element) { return element.type == 'tete'; } static isTeteDragon(itemData) { return itemData.type == 'tete'; }
static isQueueSouffle(it) { return Draconique.isQueueDragon(it) || Draconique.isSouffleDragon(it); } static isQueueSouffle(itemData) { return Draconique.isQueueDragon(itemData) || Draconique.isSouffleDragon(itemData); }
tmrLabel(linkData) { return TMRUtility.getTMRLabel(linkData.data.coord); } tmrLabel(linkData) { return TMRUtility.getTMRLabel(linkData.data.coord); }
@ -37,7 +38,8 @@ export class Draconique {
* @returns true si l'item correspond * @returns true si l'item correspond
*/ */
match(item) { match(item) {
return Draconique.isQueueDragon(item) || Draconique.isSouffleDragon(item) || Draconique.isTeteDragon(item); const itemData = Misc.data(item);
return Draconique.isQueueDragon(itemData) || Draconique.isSouffleDragon(itemData) || Draconique.isTeteDragon(itemData);
} }
/** /**
@ -110,35 +112,40 @@ export class Draconique {
/** /**
* *
* @param {*} it un item à tester * @param {*} item un item à tester
* @param {*} coord les coordonnées d'une case. Si undefined toute case du type correspondra, * @param {*} coord les coordonnées d'une case. Si undefined toute case du type correspondra,
*/ */
isCase(it, coord = undefined) { isCase(item, coord = undefined) {
return Draconique.isCaseTMR(it) && it.data.specific == this.code() && (coord ? it.data.coord == coord : true); const itemData = Misc.data(item);
return Draconique.isCaseTMR(itemData) && itemData.data.specific == this.code() && (coord ? itemData.data.coord == coord : true);
} }
find(list, coord = undefined) { find(list, coord = undefined) {
return list.find(c => this.isCase(c, coord)); return list.find(c => this.isCase(Misc.data(c), coord));
} }
async createCaseTmr(actor, label, tmr, sourceId = undefined) { async createCaseTmr(actor, label, tmr, sourceId = undefined) {
await actor.createOwnedItem({ const casetmrData = {
name: label, type: 'casetmr', img: this.img(), _id: randomID(16), name: label, type: 'casetmr', img: this.img(),
data: { coord: tmr.coord, specific: this.code(), sourceid: sourceId } data: { coord: tmr.coord, specific: this.code(), sourceid: sourceId }
}); };
await actor.createEmbeddedDocuments('Item', [casetmrData]);
} }
async deleteCasesTmr(actor, draconique) { async deleteCasesTmr(actor, draconique) {
let caseTmrs = actor.data.items.filter(it => this.isCase(it) && it.data.sourceid == draconique._id); let caseTmrs = actor.data.items.filter(it => this.isCaseForSource(it, draconique));
for (let casetmr of caseTmrs) { await actor.deleteEmbeddedDocuments('Item', caseTmrs.map(it => it.id));
await actor.deleteOwnedItem(casetmr._id); }
}
isCaseForSource(item, draconique) {
const itemData = Misc.data(item);
return Draconique.isCaseTMR(itemData) && itemData.data.specific == this.code() && itemData.data.sourceid == draconique.id;
} }
async onVisiteSupprimer(actor, tmr, onRemoveToken) { async onVisiteSupprimer(actor, tmr, onRemoveToken) {
let existants = actor.data.items.filter(it => this.isCase(it, tmr.coord)); let existants = actor.data.items.filter(it => this.isCase(it, tmr.coord));
await actor.deleteEmbeddedDocuments('Item', existants.map(it => it.id));
for (let casetmr of existants) { for (let casetmr of existants) {
await actor.deleteOwnedItem(casetmr._id);
onRemoveToken(tmr, casetmr); onRemoveToken(tmr, casetmr);
} }
} }

View File

@ -186,7 +186,7 @@ export class EffetsDraconiques {
} }
static toItems(item) { static toItems(item) {
return (item?.entity === 'Actor') ? item.data.items : (item?.entity === 'Item') ? [Misc.data(item)] : []; return (item?.documentName === 'Actor') ? item.data.items : (item?.documentName === 'Item') ? [Misc.data(item)] : [];
} }
} }

View File

@ -32,7 +32,7 @@ export class FermetureCites extends Draconique {
let existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord); let existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord);
let ouvertes = TMRUtility.filterTMR(it => it.type == 'cite' && !existants.includes(it.coord)); let ouvertes = TMRUtility.filterTMR(it => it.type == 'cite' && !existants.includes(it.coord));
for (let tmr of ouvertes) { for (let tmr of ouvertes) {
await this.createCaseTmr(actor, 'Fermeture: ' + tmr.label, tmr, souffle._id); await this.createCaseTmr(actor, 'Fermeture: ' + tmr.label, tmr, souffle.id);
} }
} }
} }

View File

@ -13,26 +13,26 @@ export class Pelerinage extends Draconique {
manualMessage() { return false } manualMessage() { return false }
async onActorCreateOwned(actor, queue) { async onActorCreateOwned(actor, queue) {
let tmr = TMRUtility.getTMRAleatoire(); let tmr = await TMRUtility.getTMRAleatoire();
await this.createCaseTmr(actor, 'Pèlerinage: ' + tmr.label, tmr, queue._id); await this.createCaseTmr(actor, 'Pèlerinage: ' + tmr.label, tmr, queue.id);
} }
code() { return 'pelerinage' } code() { return 'pelerinage' }
tooltip(linkData) { return `Votre pèlerinage en ${this.tmrLabel(linkData)}` } tooltip(linkData) { return `Votre pèlerinage en ${this.tmrLabel(linkData)}` }
img() { return 'systems/foundryvtt-reve-de-dragon/icons/tmr/pelerin.svg' } img() { return 'systems/foundryvtt-reve-de-dragon/icons/tmr/pelerin.webp' }
createSprite(pixiTMR) { createSprite(pixiTMR) {
return pixiTMR.sprite(this.code(), { return pixiTMR.sprite(this.code(), {
zIndex: tmrTokenZIndex.conquete, zIndex: tmrTokenZIndex.conquete,
alpha: 1, alpha: 1,
taille: tmrConstants.twoThird, taille: tmrConstants.full,
decallage: tmrConstants.right decallage: tmrConstants.center
}); });
} }
async onActorDeleteCaseTmr(actor, casetmr) { async onActorDeleteCaseTmr(actor, casetmr) {
await actor.deleteOwnedItem(casetmr.data.sourceid); await actor.deleteEmbeddedDocuments('Item', [casetmr.data.sourceid]);
} }
} }

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