Compare commits
621 Commits
Author | SHA1 | Date | |
---|---|---|---|
24518642a7 | |||
d917f80e88 | |||
b29027c61a | |||
6083dd41fa | |||
8969d5e0ed | |||
7d135a214f | |||
9d66a479c4 | |||
800b4a2f32 | |||
9fc21e6d97 | |||
ce7f5381ca | |||
48acdaaca6 | |||
425c6af672 | |||
4281f76dfb | |||
8ebd6ec771 | |||
14391daa0b | |||
ac29e1410e | |||
442ffe9b3a | |||
d922e4fdd5 | |||
a8dc07b4db | |||
40a47ee8a2 | |||
c5633a9fc5 | |||
7e8da49912 | |||
b524716ede | |||
72a9752820 | |||
8e578c6566 | |||
5ac9c682d9 | |||
6de19eb357 | |||
90d096a6df | |||
c733644f3a | |||
de9d3bbb48 | |||
efdffd171c | |||
8406c8434a | |||
a4b474970c | |||
135e5e46a0 | |||
969bc3b573 | |||
a9eb101c9d | |||
d53da1f011 | |||
ab0f7e563f | |||
57c41a0218 | |||
1b75decb18 | |||
551438f514 | |||
792558ac84 | |||
06aff9a3c0 | |||
7e736a00d7 | |||
b87f406093 | |||
785bd4b9ce | |||
daca86b1df | |||
aa52e26e1a | |||
f956da1fc0 | |||
10971e9e7b | |||
a3e6b95ef3 | |||
d0a5a3617c | |||
755df936fb | |||
2fa0ce5f15 | |||
b4eed49e9a | |||
af4404aab1 | |||
85804bc838 | |||
ad4baecdf2 | |||
8dc5616d7c | |||
db6b025e8f | |||
7f53757f26 | |||
879d2d10e5 | |||
016e4463bd | |||
1dfab01c4b | |||
a9cb211dba | |||
4dce510c91 | |||
14abfa8e7d | |||
1f564e0d89 | |||
ab61d5991d | |||
e3a858a9ef | |||
4cacf46ed8 | |||
5a5b5cdbb3 | |||
f90dddfbf8 | |||
d04da56c22 | |||
a87a4d371e | |||
c577fa5f29 | |||
30303330d7 | |||
ded92ddf2d | |||
2d2b75e33f | |||
a9b7dff83a | |||
75d6f78b40 | |||
979d49f96e | |||
22cab26908 | |||
23b3be246b | |||
b160ce78bc | |||
60921cfef1 | |||
12e5c94aba | |||
4dd6e1c3ff | |||
c7dfc8682d | |||
88c8a70744 | |||
3258285cea | |||
250a1abd65 | |||
2e689f642a | |||
1c68c34641 | |||
5dd5a03487 | |||
9448407e41 | |||
32adbb721f | |||
f3120f34d0 | |||
c6feac41c6 | |||
a896fdb166 | |||
1ff0de1348 | |||
ab365e9780 | |||
3739519610 | |||
f7fc7fbefb | |||
d5686b81ed | |||
5bf1ecaea3 | |||
81d826ee2e | |||
2a164f6a32 | |||
6479f00642 | |||
3cbd777e6a | |||
b377739481 | |||
d9cdfef688 | |||
d9af32b168 | |||
f13677106e | |||
e98a793506 | |||
57d35a0f9a | |||
417db33752 | |||
bf0eea693a | |||
28ee8607bb | |||
91717a3290 | |||
39ce66a26c | |||
5265c013c1 | |||
a03cee5d60 | |||
296c4babbb | |||
d9c1804a08 | |||
fa375f8092 | |||
a27e3894a0 | |||
ce8616c34e | |||
bbfac286a6 | |||
c0563efcfa | |||
c481bad81a | |||
37c281b300 | |||
9b1a179a71 | |||
8be4c3343f | |||
6af5a85dc1 | |||
c6d64e09d5 | |||
56c99c5044 | |||
a7862a25e5 | |||
f4b5a4a4d2 | |||
6a17586a6c | |||
40f7ef48c9 | |||
62dfa8a580 | |||
e71088fe2f | |||
b7cb0f0752 | |||
9b31f25640 | |||
2291eaf135 | |||
a91264cd82 | |||
864194e3b4 | |||
2c836f17e7 | |||
444e52cb49 | |||
82b0537d43 | |||
1eea07c8a8 | |||
de70ba8a3c | |||
f0e02e2205 | |||
7d9ccfaf28 | |||
830cd1c200 | |||
b9458c717e | |||
22f25b45ce | |||
dca9505925 | |||
45e9e94646 | |||
a0c7b87996 | |||
a214256d69 | |||
d2de8aa972 | |||
00ec86632f | |||
010234e001 | |||
39604afa32 | |||
aad256bfee | |||
6ebd2ee576 | |||
ac6e8b4689 | |||
387713e6f8 | |||
c69cb3c13a | |||
bda2e39e35 | |||
cb2d462cfe | |||
5f8b5b104d | |||
9fe265165b | |||
b92003ac1f | |||
a1e4bfb529 | |||
b4f0be5d64 | |||
5ff31d462f | |||
be1d109def | |||
d91bee0f42 | |||
ed222c7b6d | |||
70198a5727 | |||
bfe70c6634 | |||
09365eb744 | |||
894d4f3941 | |||
6e234411ca | |||
85acb5a255 | |||
6106e2a19e | |||
f896f1da6e | |||
9bb45c2349 | |||
5cab219e0e | |||
2de9ea49c8 | |||
1760d26014 | |||
92185d4a5b | |||
210b129934 | |||
b892068b38 | |||
3906cb0a7b | |||
5c58932a0d | |||
3b06bd382b | |||
b4a725ff12 | |||
05df6a68cc | |||
025c3483a9 | |||
97138b25c7 | |||
c0066f79c1 | |||
4db8bf95f9 | |||
a7e1ca0b07 | |||
e2c4d93413 | |||
3888efc6aa | |||
5004774a15 | |||
226afc1680 | |||
582df7e290 | |||
501f1f2e4f | |||
90d46c6a78 | |||
174ef4256a | |||
be132a9ff1 | |||
b2037a852c | |||
2137a6c403 | |||
99f5578c4f | |||
a6ae7babbe | |||
814266e649 | |||
080d05d2cd | |||
f8f889e9f9 | |||
ad80802af6 | |||
0f7b9baf51 | |||
b866c95ebd | |||
689e287ac7 | |||
40b0d7e6dc | |||
d439d73636 | |||
e91eea532d | |||
f116003d6f | |||
c3a44665c5 | |||
40b57517d8 | |||
e04586ba44 | |||
611acd4d44 | |||
9b37533bdf | |||
50d923061b | |||
e89a8ba232 | |||
b8f236fa97 | |||
74b184aa32 | |||
9c17f85fa8 | |||
599fdc752d | |||
fa890491e5 | |||
80435b6bca | |||
1a476bd5bc | |||
8d6c4565a9 | |||
6819f1c2f5 | |||
43607afc12 | |||
538cf5bdbf | |||
75507f3eca | |||
a622814295 | |||
2aa8fcb980 | |||
a65326d658 | |||
b6a203b82a | |||
7e8f642d87 | |||
91be2761f5 | |||
2ac39e3428 | |||
a162001ba4 | |||
52e1f9dfbf | |||
c586a90690 | |||
16e40b0ed8 | |||
427a950954 | |||
a7b20bdd35 | |||
3b18e0b919 | |||
ff8a5d7ba3 | |||
3aa8c0f0af | |||
8d9f09c18c | |||
9d654246c2 | |||
111fac2b2d | |||
3e99265125 | |||
28878b74fc | |||
ba8276ef37 | |||
b9e8c24461 | |||
8754ea9f5f | |||
f56ddb4a1b | |||
e80dbc7332 | |||
4c82d85e6a | |||
538058ecc6 | |||
70e42ea631 | |||
15525ef8cc | |||
5a4ef6da7e | |||
ab698b2124 | |||
4cc6e86d79 | |||
8f3d56a830 | |||
8561e3f8bc | |||
f207cb7325 | |||
b9e911a588 | |||
92e9be8b02 | |||
50a86e751d | |||
1725d4c17b | |||
3e33053ed4 | |||
baa3729568 | |||
99f29cb95b | |||
7d19860f5f | |||
40987149cc | |||
49d7c4f71d | |||
23582984cf | |||
638459049d | |||
366ca981ca | |||
c0e54c2369 | |||
f95f5b2b81 | |||
d30226cb33 | |||
5cf7dda76c | |||
9bc2593b8c | |||
efd02b40a9 | |||
feb3116c47 | |||
91a870ad91 | |||
2bbf606f30 | |||
a385b98126 | |||
8775df5285 | |||
a103239288 | |||
0b1c5d0a3d | |||
e19577eab2 | |||
c3b502ff6c | |||
db2ca2453e | |||
915283a674 | |||
621bb4ebc3 | |||
26e805cf46 | |||
657566fb11 | |||
26e8853a94 | |||
4f69d3cf78 | |||
dfe4b47452 | |||
80719d8c15 | |||
5c59f76c17 | |||
65525cfd79 | |||
042f5d0f69 | |||
19dd3b540c | |||
611b57c149 | |||
fedf8f3b29 | |||
d1ec67e485 | |||
7f7148e658 | |||
bc35c8d80e | |||
ad9e75c66d | |||
e946299810 | |||
fad894704d | |||
3365852210 | |||
d71bf27311 | |||
e6da18bebd | |||
972ae74e2c | |||
7969e74c8d | |||
84ea3a6ea9 | |||
7ada5577aa | |||
b0e28ef937 | |||
6414f76d67 | |||
dde3011f1d | |||
6dbf322efe | |||
d34fde2ba4 | |||
bc169d931b | |||
3b269b2baa | |||
dffaa29fd1 | |||
c49e2a850b | |||
a5a9cc334e | |||
43e49a0eb8 | |||
5ab551da9e | |||
2a9e98f8c7 | |||
669982ec4a | |||
34183cd1a7 | |||
f7eae3ac1e | |||
623044c936 | |||
94caf4040b | |||
d577e2d2ec | |||
050cd80dae | |||
3f098cab31 | |||
4274bce7d5 | |||
25d68d265e | |||
c1c192f710 | |||
7f64cd03f9 | |||
3ac9f487d0 | |||
fa67c3d9c1 | |||
5b443f9ac0 | |||
b0098574a0 | |||
5729f7e926 | |||
0b66c945b8 | |||
f0fc44e00f | |||
6b7c2ad2f9 | |||
0ac5d317ce | |||
f8a90fc3c3 | |||
6dd647b787 | |||
1c55491ac7 | |||
2b08678518 | |||
355f2e4088 | |||
e0862105f9 | |||
3ab48511a0 | |||
05cd02b694 | |||
56a5d06f16 | |||
f34db764cb | |||
7267cd4096 | |||
e4bd2d2f27 | |||
eb09714579 | |||
62cc3fc96b | |||
5e140546ea | |||
ab9a21f402 | |||
8e41250f64 | |||
095eed9da3 | |||
55c98d1dce | |||
b5dc14687e | |||
1208eb8ae1 | |||
a46acb7952 | |||
a68057900d | |||
57bc1b6c1f | |||
6101bc91a6 | |||
33ced5715d | |||
50db9ba709 | |||
957e31b188 | |||
74571c9966 | |||
5155fb4669 | |||
698ed75d46 | |||
37ba7166bf | |||
28af8c3c58 | |||
4a03c222d5 | |||
135546467d | |||
b5db2a9ef3 | |||
bfb7b9b6bf | |||
f0b7306885 | |||
af410c1823 | |||
bf2b387fc4 | |||
dfd915f8d1 | |||
4fe487a0ec | |||
0ec31d8ddc | |||
1bee911c35 | |||
ed7471875f | |||
f50e9cd305 | |||
a2fcb9a453 | |||
3018e3522c | |||
d16dec3278 | |||
339e128b98 | |||
b1b56c13bf | |||
b07a3e18df | |||
f446d897a7 | |||
4e89720341 | |||
c1a5bd6eb3 | |||
bfd3b0d74a | |||
da3091dc4b | |||
c7e00749c9 | |||
30d41861fa | |||
60cebe60eb | |||
ac09e1854b | |||
9ff68884ce | |||
09986115b8 | |||
511ee5f241 | |||
306d7c2150 | |||
5624bb1bf3 | |||
b588c5f7f8 | |||
6de34178b3 | |||
0c90fba346 | |||
f43b7ac651 | |||
ac436bbb25 | |||
9093eadb23 | |||
5821fc611f | |||
381242c8d0 | |||
3ca33e85b7 | |||
01399e922a | |||
c6afb8d445 | |||
4d68318d85 | |||
7811eae728 | |||
2e74ccd1fe | |||
f98ece4ffd | |||
ed068a8ddd | |||
c938778267 | |||
9056514951 | |||
1047720c24 | |||
43bcf1c336 | |||
14d4638e56 | |||
c761aeceb3 | |||
1759e6d1c3 | |||
ecb47addba | |||
b18f93fbfb | |||
19bfee7ea5 | |||
93e44bb982 | |||
12df910b3a | |||
2a3989ac2e | |||
ab884713f6 | |||
940237852b | |||
78ee23da96 | |||
862a267683 | |||
2373acc295 | |||
249d171511 | |||
018b6a32dd | |||
44ec511aa6 | |||
ff44de3b3c | |||
8101b905d8 | |||
27dd89024e | |||
69a653d1e5 | |||
bea4124388 | |||
e5bb2e9afc | |||
1d3ae9bb1a | |||
d4be2957a3 | |||
6c9d03be92 | |||
5a50917730 | |||
d285e866be | |||
ece9ab6f64 | |||
038e922f0f | |||
728c5f2f8e | |||
e6592f8333 | |||
42567e7ca0 | |||
9d1fe6d8fd | |||
f5bd0f32f4 | |||
fad29f9652 | |||
9d51631d5c | |||
d1b73e7658 | |||
54158ee10d | |||
e089bdf9c8 | |||
41ab593059 | |||
42ad4c5b26 | |||
85f8a716d4 | |||
47f305d865 | |||
407b4f82d9 | |||
c950f568fd | |||
0ed90f6177 | |||
b74fc27079 | |||
a65d4511c5 | |||
e61417c44e | |||
8ca725bd38 | |||
441a5965c7 | |||
f08c8f93da | |||
d28362bf14 | |||
e506382d18 | |||
c1cecc76b3 | |||
f2a3e1db45 | |||
b69359a47d | |||
fe6c2e2ff2 | |||
9bd13a6021 | |||
a29630f9a2 | |||
c7fd9f7596 | |||
7b18fd25c3 | |||
5c256e2c49 | |||
1c475348d5 | |||
de5d32f88f | |||
76a02d60ca | |||
724c556b9e | |||
7dfba94a11 | |||
928c7bbcfe | |||
222a06a978 | |||
b4edaf8584 | |||
3c062afd56 | |||
6de4fff403 | |||
3543f081b2 | |||
56f14e12a2 | |||
e226af5ac5 | |||
d8be37a2ec | |||
ba2d9de7b6 | |||
6b8fb3267a | |||
05d6f64a31 | |||
c0570e58b4 | |||
8389d578bc | |||
f05ef79b97 | |||
d2a8bfae4f | |||
d54834fa71 | |||
c898bf5212 | |||
a118dc7334 | |||
46401e5d63 | |||
7eb1d9f838 | |||
1d8f4ebb88 | |||
145a92f462 | |||
5148d02314 | |||
000c89b11a | |||
5d4a18aac5 | |||
34b5df637f | |||
22572ca98c | |||
a6a1c1009e | |||
288cf9162c | |||
4b1381e535 | |||
78336a3f45 | |||
3001ae44de | |||
a43ceb3188 | |||
9e95a44efd | |||
179ea0c85b | |||
3821b5bea1 | |||
2739c650d9 | |||
b101d58bee | |||
0e3d721fc7 | |||
e1e45a83be | |||
3b14e54829 | |||
615a3f1315 | |||
ca72d088cc | |||
ac89b948ca | |||
f22c4d2ec8 | |||
ffd80394d3 | |||
0959d1b18e | |||
24e58abfcc | |||
7d292c009d | |||
4bf075786c | |||
a2a04ade4c | |||
2db6895c76 | |||
e46f35ef92 | |||
9e050d3e12 | |||
81492f2857 | |||
959e751e48 | |||
b6a124b57d | |||
db2ca945a8 | |||
667d764db1 | |||
4273f5f48f | |||
6c4a8eb70f | |||
eb029e8d66 | |||
9ee14b3b56 | |||
3203fae111 | |||
755301275b | |||
f6d5dc9d7c | |||
5e9b47af1f | |||
18dfb36a78 | |||
febccd508f | |||
b147f8937b | |||
55a93b317a | |||
02a630152d | |||
ad8ac0de77 | |||
dceb6f026f | |||
ad37ee1b8e | |||
4d40e2fe59 | |||
9d7e57d9fb | |||
717029e572 | |||
d6f8976298 | |||
92e93cbbea | |||
994eaad9a9 | |||
cfed7e2afa | |||
436f9e6fa4 | |||
18a50197cd | |||
b6910612f8 | |||
4ba1ec8a2e | |||
75a0f7c322 | |||
e2a9f55740 | |||
1e0788cde8 |
74
.gitea/workflows/release.yaml
Normal file
@ -0,0 +1,74 @@
|
||||
name: Release Creation
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner."
|
||||
|
||||
#- uses: actions/checkout@v3
|
||||
- uses: RouxAntoine/checkout@v3.5.4
|
||||
|
||||
# get part of the tag after the `v`
|
||||
- name: Extract tag version number
|
||||
id: get_version
|
||||
uses: battila7/get-version-action@v2
|
||||
|
||||
# Substitute the Manifest and Download URLs in the module.json
|
||||
- name: Substitute Manifest and Download Links For Versioned Ones
|
||||
id: sub_manifest_link_version
|
||||
uses: microsoft/variable-substitution@v1
|
||||
with:
|
||||
files: 'system.json'
|
||||
env:
|
||||
version: ${{steps.get_version.outputs.version-without-v}}
|
||||
url: https://www.uberwald.me/gitea/${{gitea.repository}}
|
||||
manifest: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/system.json
|
||||
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/rddsystem.zip
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '18' # Use the node version your project requires
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Build the compendiums
|
||||
run: node ./tools/packCompendiumsToDist.mjs
|
||||
|
||||
# Create a zip file with all files required by the module to add to the release
|
||||
- run: |
|
||||
apt update -y
|
||||
apt install -y zip
|
||||
|
||||
- run: zip -r ./rddsystem.zip system.json template.json README.md LICENSE.txt assets/ fonts/ icons lang/ module/ packs/ pic/ sounds/ styles/ templates/
|
||||
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '>=1.20.1'
|
||||
|
||||
- name: Use Go Action
|
||||
id: use-go-action
|
||||
uses: https://gitea.com/actions/release-action@main
|
||||
with:
|
||||
files: |-
|
||||
./rddsystem.zip
|
||||
system.json
|
||||
api_key: '${{secrets.ALLOW_PUSH_RELEASE}}'
|
||||
|
||||
- name: Publish to Foundry server
|
||||
uses: djlechuck/foundryvtt-publish-package-action@v1
|
||||
with:
|
||||
token: ${{ secrets.FOUNDRYVTT_RELEASE_TOKEN }}
|
||||
id: 'foundryvtt-reve-de-dragon'
|
||||
version: ${{github.event.release.tag_name}}
|
||||
manifest: 'https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/system.json'
|
||||
notes: 'https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md'
|
||||
compatibility-minimum: '12'
|
||||
compatibility-verified: '12'
|
4
.gitignore
vendored
@ -8,3 +8,7 @@ todo.md
|
||||
/jsconfig.json
|
||||
/package.json
|
||||
/package-lock.json
|
||||
/packs/*/
|
||||
/packs/*/CURRENT
|
||||
/packs/*/LOG
|
||||
/packs/*/LOCK
|
||||
|
BIN
assets/scenes/9fmf9lcb3L9XO3bJ-thumb.png
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
assets/scenes/YSpVuLeMCX9tAmgn-thumb.webp
Normal file
After Width: | Height: | Size: 7.3 KiB |
704
changelog.md
@ -1,256 +1,536 @@
|
||||
---
|
||||
# v10.7 - L'os de Semolosse
|
||||
# 12.0
|
||||
## 12.0.37 - Les enchantements d'Astrobazzarh
|
||||
- les potions ont un état, seules les potions liquides sont enchantables
|
||||
- les lancements de sorts du jour sont conservés jusqu'à chateau dormant
|
||||
- lorsqu'un joueur souhaite enchanter une potion, les sorts d'enchantements/purification/permanence doivent avoir été lancés auparavant
|
||||
- on peut enchanter des gemmes exactement comme des potions
|
||||
|
||||
## v10.7.13 - l'armure de Semolosse
|
||||
- Fix: en cas d'armure variable, la détérioration diminue le dé d'armure
|
||||
## 12.0.36 - L'alchimie d'Astrobazzarh
|
||||
- Nouveautés
|
||||
- ajout d'un bouton pour enchanter les potions
|
||||
- standardisation des boutons d'actions sur les items
|
||||
- utilisations d'icones pour les actions de l'inventaire
|
||||
- Corrections:
|
||||
- la commande /tmra sans paramètres fonctionne
|
||||
- les jets d'encaissement depuis le tchat fonctionnent
|
||||
- affichage de la vie/endurance en cas de blessures et remise à neuf
|
||||
- les queues durant 12 heures ajoutées début Vaisseau ne durent plus 24 heures
|
||||
- Compendiums
|
||||
- Corrections des remedes enchantables
|
||||
- Corrections de descriptions pour proposer les jet de dés
|
||||
|
||||
## v10.7.12
|
||||
- Fix: si le MJ gère les changements de jours, l'option "sieste" de la fenêtre de repos est prise par défaut si chateau dormant n'est pas passé
|
||||
## 12.0.35 - La Solution d'Astrobazzarh
|
||||
- Fix problème d'initialisation des feuilles d'items
|
||||
|
||||
## v10.7.11 - Le Pugilat de Semolosse
|
||||
- Fix sur la projection au sol.
|
||||
## 12.0.34 - la tête d'Astrobazzarh
|
||||
- support de liens "jets de dés"
|
||||
- on peut ajouter des liens "jet de dés" dans les journaux, descriptions, notes, maladresses, ...
|
||||
- avec la syntaxe `@roll[...]` on peut ajouter le lien vers:
|
||||
- un jet de caractéristique/compétence `@roll[carac/competence/difficulte]` / `@roll[carac/difficulte]` / `@roll[carac/competence]`
|
||||
- une formule foundry `@roll[2d6]` pour lancer 2d6
|
||||
- une manipulation alchimique `@roll[couleur vert-bleu]`
|
||||
- les liens "jet avec caractéristiques" s'appliquent:
|
||||
- à tous les tokens sélectionnés
|
||||
- sinon, à l'acteur propriétaire (dans le cas d'un Item) ou à l'acteur courant
|
||||
- sinon, au personnage du joueur
|
||||
- on peut poster les liens dans le tchat pour proposer un jet aux joueurs
|
||||
- gestion des blocs secrets dans les descriptions
|
||||
|
||||
## v10.7.10 - Le Pugilat de Semolosse
|
||||
- Gestion de l'empoignade
|
||||
- Corrections sur l'initiative
|
||||
- Correction sur l'equipement des vêtements et bijoux
|
||||
## 12.0.33 - la vieillesse d'Astrobazzarh
|
||||
- retour de l'expérience pour les joueurs
|
||||
- suppression du message "Pas de caractéristique" sur les jets d'odorat-goût
|
||||
|
||||
## v10.7.9 - Le Pugilat de Semolosse
|
||||
## 12.0.32 - les rêveries d'Astrobazzarh
|
||||
- Ajout des Items Race pour gérer les ajustements liés aux races
|
||||
|
||||
- Gestion assistée de l'empoignade
|
||||
1. On selectionne sa cible (ie le token qui va être empoigné)
|
||||
2. On lance une attaque avec l'"arme" _Empoignade_
|
||||
3. A ce stade, si la victime a une arme, on rappelle le point de règle d'engagement
|
||||
(page 134), et un bouton permet de confirmer l'empoignade
|
||||
4. L'empoigneur fait son jet
|
||||
5. Si réussite, l'empoigné peut se défendre, avec gestion du premier round d'engagement
|
||||
(ie Esquive autorisée ou pas)
|
||||
- 4 bis. et 5 bis. L'empoigné, à son tour, peut tenter de se libérer, toujours en cliquant sur l'action "Empoignade"
|
||||
6. Selon le résultat, incrément/décrément des points d'emp
|
||||
7. Retour en 4., ou si 2 points d'Emp, alors 8.
|
||||
8. Affichage des options disponibles pour l'empoigneur : perte d'endurance, projection au
|
||||
sol ou entrainer au sol. Ces 3 options sont gérées automatiquement ensuite, selon le
|
||||
bouton cliqué par l'empoigneur.
|
||||
## 12.0.31 - le mausolée d'Astrobazzarh
|
||||
- Correction: les automatisation de combat jouer-MJ fonctionnentde nouveau
|
||||
|
||||
Les empoignades sont des "items" supprimées à la fin d'un combat, qui peuvent aussi être
|
||||
gérés par le MJ au cas ou. Hors combat, penser à les supprimer (ou commencer et
|
||||
arrêter un combat).
|
||||
## 12.0.30 - le cauchemar d'Astrobazzarh
|
||||
- calcul automatique du niveau des entités selon leur rêve
|
||||
- la description des créatures venimeuses contient un lien vers leur venin
|
||||
- Correction: les messages de combats ne marchaient plus (Changement combiné Foundry + rêve de Dragon)
|
||||
|
||||
## v10.7.7 - Les bobos de Sémolosse
|
||||
- Mise à jour du texte de l'heure pour les joueurs
|
||||
- L'horloge n'empêche plus de sélectionner les tokens dessous
|
||||
- _Lecture & Détection d'Aura_ sous Hypnos sont des rituels
|
||||
- _Lire les étoiles_ pour les joueurs de nouveau fonctionnel
|
||||
- Ajout de logs pour comprendre un cas d'échec des achatVente
|
||||
## 12.0.29 - L'indexation d'Astrobazzarh
|
||||
- les liens dans la descriptions des sorts pointent vers les sorts du compendium
|
||||
- la description du chrasme contient le lien vers son venin plutôt qu'un tableau
|
||||
|
||||
## v10.7.6 - L'origine des maux de Sémolosse
|
||||
- Calendrier
|
||||
- fix du ré-affichage de l'horloge qui ne marchait pas pour les joueurs
|
||||
- l'horloge ne se ferme plus sur Escape
|
||||
- amélioration d'affichage
|
||||
- couleurs jour/nuit plus marquées
|
||||
- Divers
|
||||
- correction de l'affichage de quantités diminuées d'herbes dans les contenants ouvert
|
||||
- ajout d'un bouton pour diminuer les quantités dans l'équipement (si quantité > 1)
|
||||
- ajout de la signature de l'acteur sur les blessures qu'il a causées
|
||||
## 12.0.28 - Les réserves d'Astrobazzarh
|
||||
- possibilité de mettre en réserve depuis un sort connu
|
||||
|
||||
- Magie
|
||||
- correction des bonus de cases pour les sorts en Fleuve
|
||||
## 12.0.27 - Les vêtements d'Astrobazzarh
|
||||
- Ajout de la liste des armures dans l'onglet caractéristiques
|
||||
- Ajout d'une option pour choisir une carte des TMR alternatives
|
||||
- Le Gardien peut créer des sorts en réserve parmi les sorts d'un personnage
|
||||
- Bouton pour ajouter des compétences aux créatures/entités
|
||||
- Bouton pour ajouter un personnage accordé aux entités de cauchemar
|
||||
- Correction du choix d'une cible parmi toutes les cibles pour les combats
|
||||
- Correction des ajouts de blessures (prise en compte de l'endurance et des contusions)
|
||||
- Correction des rituels de Détection et Lecture d'Aura des personnages prétirés
|
||||
- Correction des invocations
|
||||
- support de "personnages" n'ayant pas toutes les compétences
|
||||
- ajout de lien entre le sort et la créature
|
||||
- correction des liens vers les journaux
|
||||
- limitation aux compétences listées
|
||||
- acteur non lié par défaut
|
||||
- Correction des compendiums
|
||||
- l'import de personnages depuis un compendium respecte les acteurs liés/non-liés
|
||||
- les modèles de voyageurs sont liés par défaut
|
||||
- les modèles de personnages non joueurs sont non-liés par défaut
|
||||
|
||||
## v10.7.5 - La montre-gousset de Sémolosse
|
||||
- Amélioration de la fenêtre calendrier
|
||||
* plus compacte
|
||||
* horloge analogique (optionnelle)
|
||||
* minimizable (juste la barre de titre)
|
||||
* normalement compatible pop-out
|
||||
## 12.0.26 - Astrobazzarh le Haut-rêvant
|
||||
- bouton pour le don de haut-rêve en un clic
|
||||
- les compétences de draconic ne sont plus précédées de "Voie de"
|
||||
- migration des compétences & compendiums
|
||||
- Correction feuille simplifiée qui ne s'affichait pas en cas de sort variable
|
||||
|
||||
## v10.7.4 - Les ligatures de Sémolosse
|
||||
- Corrections diverses
|
||||
- Correction des boutons pour déclencher un sort en réserve avec réserve en sécurité ou réserve extensible
|
||||
- le lien pour les jets de vie suite à une blessure critique est remplacé par un bouton
|
||||
- déplacement des tâches et boutons de chirurgie dans l'onglet savoirs et tâches
|
||||
- correction de l'affichage des bonus de cases des sorts
|
||||
- corrections des queues non-refoulables dans le compendium
|
||||
## 12.0.24 - Les ajustements d'Astrobazzarh
|
||||
- amélioration
|
||||
- meilleure gestion des noms des voies de draconic
|
||||
- affichage du détail des sorts avec le nom de voie, 'court', la difficulté, le coût
|
||||
- corrections
|
||||
- les tas dans les conteneurs peuvent être désempilés sans rendre le conteneur inutilisable
|
||||
- les conteneurs ne peuvent plus être empilés (pour éviter que le contenu de Schroedinger quand on les sépare)
|
||||
- on peut maintenant saisir et supprimer les bonus de cases de manière intuitive
|
||||
|
||||
## 12.0.23 - La bibliothèque d'Astrobazzarh
|
||||
- corrections mineures
|
||||
- meilleure gestion de la parade des armes naturelles
|
||||
- cas de "User lacks permission to update" pour les blessures et les StatusEffects
|
||||
- risque de message d'encaissement non affiché
|
||||
- support de sorts à voies multiples
|
||||
- correction de compendiums
|
||||
- résistance des armes mise à jour
|
||||
- voies multiples pour las sorts de Lecture d'aura, Détection d'aura et Annulation de magie
|
||||
- améliorations "Scriptarium"
|
||||
- recherche des compétences sans accents pour permettre les noms accentués (standard Scriptarium)
|
||||
- affichage r1+ des sorts à coût variable dans la feuille simplifiée
|
||||
- affichage de Corps à corps pour le combat à mains nues dans la feuille simplifiée
|
||||
- dans les compendiums, les compétences Écriture et Épée ont une majuscule accentuée. Les Épée dans le compendium d'équipements référence le nom de compétence accentué.
|
||||
|
||||
## v10.7.3 - Les tisanes de Sémolosse
|
||||
- Soins
|
||||
- on peut de nouveau boire une potion de soins enchantée
|
||||
- les potions non enchantées donnent de nouveau un bonus au prochain jet de récupération
|
||||
- Une fois les soins complets faits, le bonus aux soins complets fournis par les premiers soins est masqué
|
||||
## 12.0.21 - La nomination d'Astrobazzarh
|
||||
- Les noms pour les messages dans le tchat sont maintenant ceux des tokens plutôt que ceux des acteurs
|
||||
- Fix: le choix des effets dans les options s'affiche correctement
|
||||
|
||||
- Horloge
|
||||
- A l'heure de Couronne pile, les aiguilles des heures et des minutes pointent sur couronne (comme une montre) au lieu d'avoir l'aiguille des heures 15° à gauche
|
||||
## 12.0.20 - Le tableau d'Astrobazzarh
|
||||
- Ecran d'accueil officiel Scriptarium
|
||||
|
||||
## v10.7.2 - les maux de dents de Semolosse
|
||||
- correction des récupérations de blessures
|
||||
- la fin de château dormant se passe normalement
|
||||
## 12.0.19 - La témérité d'Astrobazzarh
|
||||
- Fix
|
||||
- les défenses des créatures sont correctement filtrées
|
||||
- le lancer d'initiative pour tous les personnages/PNJs fonctionne correctement
|
||||
- les lieux et commerces n'ont pas d'initiative
|
||||
|
||||
## v10.7.1 - L'os de Semolosse
|
||||
- Fix rapide sur les jets de carac qui n'étaient plus possibles
|
||||
## 12.0.18 - A la barbe d'Astrobazzarh
|
||||
- Améliorations sur la feuille de PNJ simplifiée
|
||||
- Ajout du portrait
|
||||
- Ajout du corps à corps
|
||||
- Affichage du niveau d'esquive
|
||||
- Un clic sur l'initiative permet de lancer l'initiative
|
||||
- les boutons +/- pour la vie, l'endurance et la fatigue changent si on est à la valeur normale
|
||||
- un clic sur l'endurance effectue un jet d'endurance
|
||||
- Fix
|
||||
- les achats des commerces sont de nouveau possibles
|
||||
- la commande /astro fonctionne de nouveau
|
||||
- le nombre d'utilisations d'items est réinitialisé à chaque round et fin de combat
|
||||
- la difficulté de parade pour les armes à distances n'est plus indiquée
|
||||
- les propositions d'armes de parade sont corrigées
|
||||
- Ajout d'un indicateur pour les armes de parade nécessitant une significative
|
||||
|
||||
## v10.7.0 - L'os de Semolosse
|
||||
- gestion des blessures en items
|
||||
- soins du token ciblé par menu contextuel (comme le combat)
|
||||
- automatisation des soins et de l'affichage de l'avancement des soins
|
||||
- support des changements d'opérants
|
||||
## 12.0.16 - Le secret d'Astrobazzarh
|
||||
- Fix: les jets envoyés messages uniquement au MJ ne sont plus envoyés à tous les autres joueurs (et dupliqués)
|
||||
- Les noms affichés dans les automatisations de combat sont maintenant ceux des tokens plutôt que ceux des acteurs
|
||||
- Ajout d'une option pour la localisation des blessures
|
||||
|
||||
---
|
||||
# v10.6 - Les recherches de Pralinor le Goûteux
|
||||
## 12.0.15 - Le messager d'Astrobazzarh
|
||||
- Correction des faces de dés personalisés dice-so-nice
|
||||
- Les messages de maladies ne sont plus publics
|
||||
- Les messages privés dans les TMR sont aussi envoyés au GM
|
||||
- Les informations de compétences pouvant augmenter s'affichent comme tooltips
|
||||
- Amélioration du rendu des tables de compendiums (commande /table)
|
||||
|
||||
## v10.6.25 - Fix sur l'astrologie
|
||||
## 12.0.14 - Les légions d'Astrobazzarh
|
||||
- Feuille de PNJ:
|
||||
- boutons standard (encaissement, ...)
|
||||
- boutons pour ajuster les compteurs
|
||||
- visualisation des blessures
|
||||
- click sur blessure pour ajouter/enlever
|
||||
- gestion des armes
|
||||
|
||||
## v10.6.22 - le nuage de lait dans le thé de Pralinor
|
||||
- Amélioration de l'affichage de l'horloge
|
||||
- Fix: affichage des points de guérison dans les potions
|
||||
## 12.0.13 - La Chance d'Astrobazzarh
|
||||
- Fix: jets de caractéristiques
|
||||
|
||||
## v10.6.21 - La théière de Pralinor
|
||||
- Astrologie
|
||||
- le thème astral est directement dans la fenêtre d'astrologie
|
||||
- la roue des heures sert d'horloge
|
||||
- sélectionner un personnage ajuste le thème astral pour son heure de naissance
|
||||
- sélectionner le nombre astral d'un jour ajuste le thème astral
|
||||
## 12.0.12 - L'étalage d'Astrobazzarh
|
||||
- Fix: On peut de nouveau vendre des items sans propriétaire, depuis les compendiums ou depuis l'onglet des Objets
|
||||
- Début de Feuille PNJ au format des encarts Scriptarium
|
||||
- support des jets de caractéristiques
|
||||
- support des jets de compétences
|
||||
|
||||
- Fix: les PNJs peuvent de nouveau dormir
|
||||
## 12.0.11 - Le scriptorium d'Astrobazzarh
|
||||
- ajout d'un bouton pour générer les éléments de description d'un personnage
|
||||
- ajout du logo en background dans la liste des systèmes Foundry
|
||||
- ajout d'un champ pour le métier
|
||||
- export scriptarium
|
||||
- encodage de l'export en windows-1252
|
||||
- export de l'esquive avec armure et sans armure
|
||||
|
||||
## v10.6.20 - Les Oracles de Pralinor: vous mangerez à Couronne
|
||||
- Ajout de la fenêtre pour effectuer un thème astral
|
||||
## 12.0.9 - 12.0.10 - Le scriptorium d'Astrobazzarh
|
||||
- corrections de l'export scriptarium
|
||||
- ajout d'une fonction avancée pour un exporter "scriptarium" des personnages
|
||||
|
||||
## v10.6.19 - La cerise de Pralinor
|
||||
- les joueurs peuvent chercher dans les commerces avec un droit limité/observateur
|
||||
- simplifications des fins de tours et nombre d'utilisations
|
||||
- ajout du _Haubert d'Oniros_ dans le compendium de sorts
|
||||
## 12.0.8 - La quincaillerie d'Astrobazzarh
|
||||
- le propriétaire est indiqué dans les feuilles d'équipements/compétences/...
|
||||
- Ecaille d'efficacité
|
||||
- l'écaille d'efficacité est prise en compte même si on n'utilise pas le ciblage en combat
|
||||
- l'écaille d'efficacité est prise en compte pour l'initiative
|
||||
- Corrections
|
||||
- l'état général est pris en compte pour les initiatives
|
||||
- le tooltip de l'initiative affiche correctement l'initiative
|
||||
|
||||
## v10.6.17 - Les désordres de Pralinor
|
||||
- le contenu des casseroles et autres contenants est maintenant trié dans l'ordre alphabétique
|
||||
- les objets dupliqués du compendium d'équipement sont de nouveaux uniques
|
||||
## 12.0.7 - La propriété d'Astrobazzarh
|
||||
- correction des opérations faites à la création d'un Item:
|
||||
- la durée des queues/rencontres/souffles
|
||||
- les effets draconiques d'un souffle/queue
|
||||
- mise à jour des points de tâche des blessures lors des soins
|
||||
- pas d'expérience sur les particulières quand aucun MJ n'est connecté
|
||||
- Le drag&drop d'un acteur depuis la liste des acteurs sur la fiche
|
||||
d'une entité incarnée permet d'accorder le personnage
|
||||
- Les messages pour résister aux possessions/conjuration sont envoyées
|
||||
au défenseur
|
||||
- Les messages pour résister aux empoignades sont envoyées au défenseur
|
||||
- la commande /voyage affiche maintenant le total de fatigue pour chaque voyageur
|
||||
- la commande /voyage affiche maintenant les compétences liées au terrain
|
||||
|
||||
## v0.6.16 - Le pardon de Pralinor
|
||||
- Ajout d'un commerce _Liste d'équipement_ dans les archétypes de PNJs
|
||||
- Séparations d'équipements groupés et corrections de quelques objets & herbes
|
||||
- On peut éditer les armes stockées dans un commerce
|
||||
## 12.0.6 - Le bazar d'Astrobazzarh
|
||||
- Corrections de l'inventaire en bazar:
|
||||
- un problème pouvait survenir en déplaçant les objets
|
||||
l'inventaire, qui fait qu'un conteneur se retrouve récursivement dans son
|
||||
propre contenu, ce qui empêche d'ouvrir la feuille d'acteur.
|
||||
- un objet non-conteneur pouvait dans certains cas avoir un pseudo contenu
|
||||
- un objet pouvait être considéré comme contenu, sans être présent dans un
|
||||
conteneur (et donc non affiché)
|
||||
- vider les conteneurs supprime correctement toutes les informations liées
|
||||
aux conteneurs/contenus
|
||||
- Les messages pour les tirages dans le compendium utilisent le "roll mode"
|
||||
courant pour leur visibilité
|
||||
- Fix: restaurer la compatibilité Foundry 11
|
||||
|
||||
## v10.6.15 - les digestifs de Pralinor
|
||||
- amélioration des messages de sommeil (nombre d'heure dormies, uniquement les
|
||||
récupérations de rêve en dessous du seuil, affichage de la récupération d'endurance
|
||||
qui avait disparu, meilleur message sur le jet de moral)
|
||||
- les insomnies ne durent bien que 12h draconique à partir du prochain
|
||||
Chateau Dormant (elles pouvaient durer 3 nuits suite à une erreur).
|
||||
- la recherche dans l'équipement affiche correctement les conteneurs dans lesquels les
|
||||
objets trouvés sont rangés
|
||||
## 12.0.5 - Les mauvais jours d'Astrobazzarh
|
||||
- Fix: on peut de nouveau ouvrir l'édition de calendrier
|
||||
- Fix: on ne peut plus ouvrir plusieurs fenêtres de lancer de sort
|
||||
- Fix: Failed to execute 'getComputedStyle' on 'Window'
|
||||
|
||||
## v10.6.14 - la digestion de Pralinor
|
||||
- Chateau dormant
|
||||
- la situation du jet de moral peut être choisie lorsque l'on dort
|
||||
- les queues de dragon "insomnie" empêchent de dormir, et de rêver
|
||||
- ajout d'une option pour meilleure gestion de Chateau Dormant par le MJ
|
||||
- avec cette option, à la fin Chateau Dormant, une fenêtre permet au gardien de
|
||||
positionner pour chaque joueur:
|
||||
- le stress de la journée
|
||||
- les heures de sommeil
|
||||
- la situation du jet de moral (neutre/heureux/malheureux)
|
||||
## 12.0.4 - La plaie d'Astrobazzarh
|
||||
- **Support V12**
|
||||
- Fix: les boutons d'encaissement dans le tchat fonctionnent de nouveau
|
||||
- Fix warnings sur "Die" et AudioHelper
|
||||
|
||||
- l'affichage des heures Chateau Dormant et Poisson Acrobate est correct
|
||||
- le jet de moral en situation neutre fait maintenant retourner le moral vers 0, et
|
||||
n'affecte plus un moral à 0.
|
||||
## v10.6.13 - la cave de Pralinor
|
||||
- on peut maintenant chercher dans l'inventaire des commerces
|
||||
- l'inventaire est correctement affiché en entier après suppression de la recherche
|
||||
- le message de chateau dormant reflète correctement un jet de moral neutre qui passe le moral de 0 à +1
|
||||
## 12.0.3 - L'hémorragie d'Astrobazzarh
|
||||
- **Support V12**
|
||||
- On peut de nouveau ouvrir un acteur blessé après redémarrage du monde
|
||||
- On peut de nouveau ouvrir les Items avec une rareté par environnement
|
||||
- Le choix de ne plus afficher les demandes de suppression est bien pris en compte
|
||||
|
||||
## v10.6.12 - l'index de Pralinor
|
||||
- On peut désormais chercher dans l'inventaire comme dans les compétences
|
||||
## 12.0.2 - Les pluies d'Astrobazzarh
|
||||
- **Support V12**
|
||||
- correction des actions techniques déleguées au MJ qui bloquaient les fenêtre de lancer de dés des joueurs (et plein d'autres)
|
||||
- la fenêtre de calendrier s'ouvre correctement
|
||||
- les dés draconiques peuvent de nouveau faire plus que 0
|
||||
- adaptation de la fenêtre de recherche
|
||||
- correction des comparaisons de version pour les migrations automatiques
|
||||
- correction des roll.eveluate: l'option async est maintenant standard
|
||||
- correction des templates liés aux selections
|
||||
- correction de l'ajustement de luminosité de la scène selon l'heure
|
||||
- correction des images d'effets sur les tokens
|
||||
- correction de la vente par le tchat: seul le premier acheteur pouvait acheter
|
||||
- correction d'erreurs intempestives 'User ... lacks permission to update ...'
|
||||
|
||||
## v10.6.11 - l'empoisonnement de Pralinor
|
||||
- La récupération est bloquée par les maladies. Pas de récupération de vie ou de blessures possibles sous l'effet d'un poison ou d'une maladie
|
||||
- ajout d'un "poison" pour bloquer la récupération sous Griffe Morbide de Thanatos.
|
||||
Ajout du lien vers l'objet du compendium dans la description MJ,, qui pourra donc
|
||||
ajouter ce "poison" à la victime pour empêcher ses guérisons de vie ou blessure.
|
||||
# 11.2
|
||||
## 11.2.21 - Le questionnement d'Akarlikarlikar
|
||||
- Une confirmation spécifique est demandée pour monter dans les terres médianes en cas de rencontre en attente
|
||||
- L'expérience en caractéristique sur les jets de chance et rêve actuels est mise dans la caractéristique correspondante
|
||||
- Les effets s'appliquent correctement sur les créatures
|
||||
- La date et l'heure (draconiques) sont affichées dans les messages du tchat
|
||||
|
||||
## v10.6.10
|
||||
- Correction de l'édition des description
|
||||
- Amélioration des descriptions d'alchimie:
|
||||
- difficulté calculée automatiquement
|
||||
- Température pour les couleurs
|
||||
- La sustentation n'est plus concaténée dans certains cas (ce qui donnait 2+2=22)
|
||||
## 11.2.20 - Le soulagement d'Akarlikarlikar
|
||||
- L'option "ajout de la difficulté d'attaque à l'encaissement" est affichée comme un modificateur d'encaissement
|
||||
- Les options d'encaissement alternatives fonctionnent avec la validation de l'encaissement par le gardien
|
||||
- La fenêtre d'astrologie du gardien affiche toutes les heures lues par un personnage
|
||||
- Si aucune expérience n'est gagnée, les autres effets à appliquer (comme la récupération de seuil après avoir vaincu un rêve de Dragon) s'appliquent normalement
|
||||
- Les tooltips de Foundry sont lisibles
|
||||
- On n'accorde plus les entités de cauchemar deux fois quand le gardien valide les encaissements
|
||||
- Les messages de récupération de rêve en cas de Rêve de Dragon sont clarifiés
|
||||
|
||||
## v10.6.8 : les bon mots de Pralinor
|
||||
- Dans la fenêtre de _recherche et tirages_, possibilité de chercher sur le nom des objets en plus des autres critères
|
||||
## 11.2.19 - Les hémorroïdes d'Akarlikarlikar
|
||||
- La validation des jets d'encaissement par le Gardien fonctionne de nouveau
|
||||
|
||||
## v10.6.7 : les grumelés de Pralinor
|
||||
- les objets peuvent être utilisés depuis la fenêtre d'un conteneur
|
||||
- dans les fenêtres de contenants, le contenu est correctement indenté
|
||||
- la présentation du contenu d'un sac est améliorée
|
||||
- le bouton Nouvel Objet n'est affiché que si on est propriétaire de l'acteur
|
||||
- la fenêtre de vente permet de nouveau de choisir les quantités à vendre
|
||||
## 11.2.18 - Le bourrichon d'Akarlikarlikar
|
||||
- Les différentes listes de la feuille de personnage ont maintenant le bouton pour envoyer dans le tchat
|
||||
|
||||
## v10.6.6
|
||||
- Corrections d'armes rudimentaires
|
||||
- Inversion: Taille puis poids
|
||||
- Suppression d'une ligne de caractéristique vide (causée par la beauté)
|
||||
- Les messages liés aux compétences troncs deviennent des notifications
|
||||
## v10.6.5
|
||||
- Le +dom est de nouveau affiché
|
||||
- L'édition de caractéristiques des créatures fonctionne de nouveau
|
||||
## 11.2.17 - Le cache-oeil d'Akarlikarlikar
|
||||
- Le titre des fenêtre d'objet affiche de nouveau le type traduit
|
||||
- Les tooltips des boutons edit/delete sont maintenant en Français
|
||||
- La case à cocher "Cacher les points de tâches" fonctionne de nouveau
|
||||
- Les personnages non-liés ne sont plus dans les liste de personnages joueurs pour le repos, le stress, la fatigue
|
||||
- L'utilisation de Thanatos est visible dans l'onglet Haut-Rêve pour indiquer que la prochaine queue est une ombre
|
||||
- La fenêtre des TMRs ne devrait plus afficher une zone noire au lieu de la carte.
|
||||
|
||||
## v10.6.4 - La sénilité de Pralinor
|
||||
- Fenêtre _Recherches et tirages_
|
||||
- les résultats de recherches sur plusieurs compendiums sont triés
|
||||
- lors de recherches avec un ou des milieux sélectionnés:
|
||||
- le filtre sur la rareté utilise la rareté dans ces milieux
|
||||
- les tirages se basent sur la fréquence la plus élevées dans ces milieux
|
||||
- les filtres par utilisation prennent les potions en compte
|
||||
- les remèdes ont une catégorie de potion 'Remède' (et correspondent à une utilisation médicale)
|
||||
- ajout d'un filtre d'utilisation 'cuisine'
|
||||
## 11.2.16 - Le Tri d'Akarlikarlikar
|
||||
- Tri alphabétique des items dans la fenêtre de création
|
||||
- Mise à jour comptage de monde
|
||||
|
||||
## 11.2.15 - La Table d'Akarlikarlikar
|
||||
- Tirage automatique de la foce d'une rencontre (via la commande /tmrr)
|
||||
- Ajout de boutons pour ajouter des blessures "complètes" (ie avec perte d'endurance/vie)
|
||||
|
||||
# Divers
|
||||
- fix du cas où la transformation de 0 points de stress était concaténé, (passage de 29 à 290 avec 0 points transformés)
|
||||
- suppression du compendium de taches courantes, désormais inutile
|
||||
## 11.2.14 - Les petits pas d'Akarlikarlikar
|
||||
- Correction sur la gestion de la surprise
|
||||
- Ordre des messages sur les cases humides
|
||||
|
||||
## v10.6.3 - le baba-brandevin de Pralinor
|
||||
- les tâches de Soins sont maintenant déplacées à côté des blessures
|
||||
- on peut créer les tâches de soins directement avec un bouton par gravité.
|
||||
## 11.2.13 - Les cent pas d'Akarlikarlikar
|
||||
- Ajout de la commande /voyage pour gérer la fatigue de marche des voyageurs
|
||||
|
||||
- le round n'est plus bloqué si un acteur est sonné
|
||||
- un rare cas d'initiative négative pouvait empêcher de faire une initiative (à cause de l'état général)
|
||||
- dans une circonstance inconnue, une rencontre pouvait disparaître lors de la maîtrise. Ajout d'un message pour essayer d'obtenir des détails sur ce cas, et ajout d'une sécurité pour retrouver la rencontre (qui est conservée par la fenêtre de choix d'action).
|
||||
- les objets temporels (queues, souffles, poisons, maladies...) créés avant la gestion temporelle ne pouvaient pas être édités.
|
||||
- les particulières sur les jets de résistance de rêve actuel ne rapportent qu'un point d'expérience (p191)
|
||||
- pour lutter contre l'alcoolisme, les jets d'éthylisme sont considérés comme des jets de résistance, et n'apportent qu'un point d'expérience.
|
||||
## v10.6.2 - Le méli-mélo de Pralinor
|
||||
- Fenêtre _Recherches et tirages_
|
||||
- support de la recherche dans les compendiums choisis
|
||||
- suppression des commandes `/table milieu` et `/tirer milieu` (remplacées par la fenêtre de recherche)
|
||||
- ajout de fréquences à tous les équipements
|
||||
## v10.6.1 - Les recherches de Pralinor
|
||||
- Fenêtre _Recherches et tirages_
|
||||
- Amélioration des filtres de cuisine/utilisation
|
||||
- Ajout de catégories pour les poisons, urtiquants, ...
|
||||
- Bouton "Effacer les filtres" plus clair
|
||||
- Drag&drop depuis la recherche
|
||||
- Reprise du compendium
|
||||
- pour les plantes vénéneuses
|
||||
- pour les plantes venimeuses
|
||||
- ajout de sust pour les champignons et autres plantes comestibles
|
||||
## 11.2.12 - Le somnifère d'Akarlikarlikar
|
||||
- Fix: les potions enchantées n'empêchent plus de finir correctement Château Dormant
|
||||
|
||||
- Affichage de l'image du token pour les commerces non liés
|
||||
- Les pièces d'or sont appelées 'Dragon'
|
||||
## 11.2.11 - Le miroir d'Akarlikarlikar
|
||||
- Changement des images de compétence de créatures morsure/pinces pour être dans le thème
|
||||
- Suppression de la bordure autour des portraits d'acteurs, remplacés par un légèr éclaircissement du fond
|
||||
- Fix: le refoulement ajoute correctement un souffle et revient à 0 en cas d'échec
|
||||
|
||||
## v10.6.0 - Les recherches de Pralinor le Goûteux
|
||||
- Fenêtre _Recherches et tirages_
|
||||
- ajout de la fenêtre _Recherches et tirages_ avec filtres paramétrables
|
||||
- ouverture de la fenêtre: commande `/tirage` ou macro disponible dans les macros du système
|
||||
- support des équipements, faune & flore (depuis les compendiums configurés par défaut)
|
||||
- nombreux choix à activer
|
||||
- possibilité de montrer les objets correspondant à la sélection
|
||||
- possibilité de faire un tirage parmi ces objets (en prenant en compte la fréquence)
|
||||
## 11.2.10 - Les expériences d'Akarlikarlikar
|
||||
- En cas d'expérience des caractéristiques dérivées,
|
||||
- si plusieurs caractéristiques pourraient recevoir l'expérience, une fenêtre demande au joueur
|
||||
- si une seule caractéristique peut recevoir de l'expérience, c'est attribué automatiquement
|
||||
- Si la force est au maximum pour la taille personnage, on ne peut plus gagner d'expérience
|
||||
|
||||
- Plantes & pèche
|
||||
- séparation des ingrédients et plantes comestibles
|
||||
- retour des poissons dans les compendiums
|
||||
- ajout d'un lien depuis les plantes toxiques/dangereuses vers la maladie/poison correspondante
|
||||
## 11.2.9 - La barbe d'Akarlikarlikar
|
||||
- Amélioration des textes de tooltips
|
||||
- Les tooltips sont plus dans le thème de couleur du système Rêve de Dragon
|
||||
- Ajouts d'icones pour les attaque/initiative/soins dans les raccourcis sur les tokens (HUD)
|
||||
- Ajout d'une icône et transformation en bouton du lien pour accéder à l'astrologie et aux chiffres astraux
|
||||
- Suppression de message de log inutile sur chaque point de coeur
|
||||
- On peut désactiver l'ajustement astrologique sur les jets de chance (pour des jts de chances non liés à une heure)- Fix: suppression de quelques cas d'erreur lors de l'ouverture des TMR
|
||||
- Fix: suppression du warning de depréciation effects flags.core.statusId
|
||||
- Les sorts en réserve en fleuve sont indiqués sur toutes les cases fleuve
|
||||
- Changement de l'icône d'état d'empoignade pour suivre les couleurs des autres icônes d'état
|
||||
|
||||
## 11.2.8 - L'éclairage d'Akarlikarlikar
|
||||
- l'ajustement de la lumière jour/nuit s'étale sur moins de temps (vaisseau et Lyre)
|
||||
- les nouveaux tooltips ne masquent plus l'information d'expérience
|
||||
- les jets de dés pour maîtriser les rencontres fonctionnent de nouveau
|
||||
|
||||
## 11.2.7 - Les explications d'Akarlikarlikar
|
||||
- Ajout de tooltips sur la plupart des boutons, liens clickables, objets, tâches, ...
|
||||
- Fix: on peut de nouveau regarder l'inventaire avec les droits limités/observateur
|
||||
|
||||
## 11.2.6 - Les réveils difficiles d'Akarlikarlikar
|
||||
- Les changements de points de Cœur sont temporaires jusqu'à fin Château Dormant
|
||||
- Fix: tous les petits fixes (feuille qui s'ouvre plus, compagnons animaux, potions qui bloquent Château Dormant, ...)
|
||||
|
||||
## 11.2.2 - Les tendres moments d'Akarlikarlikar
|
||||
- On peut maintenant avoir des points de Cœur pour des suivants/compagnons
|
||||
- diminuer les points de coeurs fait perdre du moral
|
||||
- on peut proposer un tendre moment
|
||||
- les jets de volonté peuvent être ajustés selon les points de Cœur
|
||||
- Fixes
|
||||
- La résistance est de 1 par défaut pour les équipements
|
||||
- Les armes de créatures sont de nouveau utilisables depuis les tokens
|
||||
- Pas de notifications de signe draconique quand on regarde les TMR sans monter
|
||||
- Correction d'un problème de contextes WebGL causé par des ouvertures/fermetures de TMRs
|
||||
- On peut maintenant prendre un objet d'un acteur-token pour l'ajouter à un autre acteur
|
||||
- On ne peut plus donner d'objets d'un acteur à un acteur-token
|
||||
- L'état général est correctement calculé, affiché, et utilisé pour les animaux
|
||||
- On peut ajouter des blessures manuellement aux animaux
|
||||
- Le texte de la carte de Tarot "Le Gibet" est corrigé
|
||||
- Sur Firefox, le calendrier est correctement initialisé, les ajustements astrologiques
|
||||
ne bloquent plus les jets de dés
|
||||
|
||||
## v11.2.1 - La technique d'Akarlikarlikar
|
||||
- On peut créer des armes pour Corps à corps et Esquive. Barreaux de chaise, armes improvisées, techniques d'art martiaux, pas de côté pour faire trébucher l'adversaire... A vous de voir comment imaginer de nouvelles "armes".
|
||||
- Les armes avec une résistance de 0 ne peuvent pas être utilisées, une image et un rappel indiquent qu'elles sont cassées
|
||||
|
||||
Vu qu'elles ne peuvent pas être utilisées, permet de savoir pourquoi
|
||||
## v11.2.0 - Les Terres médianes d'Akarlikarlikar
|
||||
- Les TMRs sont redimensionables
|
||||
- Nouveaux graphismes plus lisibles dans les TMRs
|
||||
- Nouveau code couleur des icônes dans les TMR:
|
||||
- noir: case innaccessible
|
||||
- rouge: empêche l'usage du haut-rêve
|
||||
- vert: bonus de tête de dragon permanent
|
||||
- bleu: la case doit être vaincue
|
||||
- blanc: effet temporaire (sort en réserve, présent des cités)
|
||||
- Fix: les déplacements aléatoires prennent bien compte des colonnes paires/impaires
|
||||
- Fix: Le Tricollet prend deux "L"
|
||||
- Fix: Les jets d'encaissement forcés par le gardien à un résultat inférieur à 11 ne peuvent plus donner un deuxième d10 négatif
|
||||
|
||||
# v11.1
|
||||
## v11.1.6 - Les dissections de Werther de Zloth
|
||||
- Fix: on peut de nouveau donner des compétences aux créatures
|
||||
- Fix: le délai de guérison d'une blessure rétrogradée est correctement appliqué
|
||||
- Fix: l'encaissement à valider par le MJ fonctionne de nouveau
|
||||
|
||||
## v11.1.5 - Werther de Zloth l'Onirique
|
||||
- Fixes:
|
||||
- la demande de défense ne marchait plus
|
||||
- la tête réserve extensible crée bien une case de réserve extensible (à modifier)
|
||||
- le souffle trou noir ajoute bien une case de trou noir
|
||||
- la queue urgence draconique ne se transforme plus en idée fixe s'il y a des sorts en réserve
|
||||
- l'ajout d'une nouvelle queue ne supprime plus l'insomnie
|
||||
- Amélioration des jets de vie
|
||||
- un 1 sur le jet de vie est une réussite même si le personnage est dans le coma
|
||||
- le temps avant le prochain jet est calculé et affiché
|
||||
- un 20 sur le jet de vie signifie la mort immédiate
|
||||
- si on dépasse le S.Const, le personnage est bien indiqué comme mort
|
||||
- pas de jets de vie pour les morts
|
||||
|
||||
## v11.1.4 - Werther de Zloth l'Onirique
|
||||
- Ajout du facteur de significative à côté du pourcentage dans le résultat des jets de dés pour rappeler que le pourcentage n'est pas diviasé
|
||||
- Fix: dans les TMRs, les tooltips affichent bien les informations de tous les effets sur la case
|
||||
- Fix: la fatigue et l'éthylisme sont de nouveau pris en compte dans le calcul de l'éthylisme
|
||||
- Fix: Le MJ peut correctement masquer les points de tâche requis
|
||||
- Fix: le jet d'appréciation n'utilise pas la compétence
|
||||
- Fix: la qualité négative n'est pas exotique, elle est juste mauvaise: on n'utilise pas la cuisine pour se retenir de jeter l'assiette
|
||||
- Esthétique: ne pas afficher "+0" pour les ajustements de jets/encaissement
|
||||
|
||||
## v11.1.2 - Les vertèbres de Werther de Zloth
|
||||
- Fix: les jets d'encaissement fonctionnent de nouveau normalement
|
||||
- Macro "Mon personnage" permettant au joueur d'accéder à sa feuille de personnage depuis la barre de macros
|
||||
|
||||
## v11.1.1 - Les fumebols de Werther de Zloth
|
||||
- Fix: on peut de nouveau afficher les vues détaillées
|
||||
- Fix: on peut ouvrir les sacs et contenants portés par les véhicules et créatures
|
||||
- Fix: cuisiner du gibier prend maintenant bien les proportaions en compte
|
||||
|
||||
## v11.1.0 - Les choix de Werther de Zloth
|
||||
- Les options suivantes peuvent être désactivées:
|
||||
- La transformation de stress à Château Dormant
|
||||
- La récuperation de chance à Château Dormant
|
||||
- La récupération d'éthylisme
|
||||
- La récupération de rêve (y compris fleurs de rêve et Rêves de Dragon: la rencontre a lieu, mais ne donne pas de rêve)
|
||||
- Le jet de moral de Château Dormant
|
||||
- Séparation des véhicules dans leur propre acteur
|
||||
- Séparation des entités dans leur propre acteur
|
||||
- Séparation des créatures dans leur propre acteur
|
||||
- La fenêtre de signes draconiques ne sélectionne plus tout les haut-rêvants par défaut
|
||||
- Un nouveau personnage a automatiquement son token relié
|
||||
- corrections de bugs
|
||||
- si on n'utilise pas les règles de fatigues, un reflet de rêve pouvait garder le Haut-rêvant dans les TMRs pour toujours
|
||||
- certaines macros ne marchaient pas pour les créatures/entités/véhicules/commerces
|
||||
- en cas de charge, les particulières sont toujours en force (p125)
|
||||
|
||||
# v11.0
|
||||
## v11.0.28 - les fractures de Khrachtchoum
|
||||
- La gravité de la blessure est affichée dans le résumé de l'encaissement
|
||||
- Lors du changement d'acteur pendant le round
|
||||
- le message annonçant le joueur dont c'est le tour ne contient plus d'informations de santé
|
||||
- un message avec les informations de santé est envoyé au Gardienn et au propriétaire du token.acteur
|
||||
- le jet de vie est bien fait par le token si besoin
|
||||
- seul les propriétaires peuvent faire les jets de vie
|
||||
- Amélioration de la fenêtre de jets
|
||||
- le type de dégâts pour les attaques est toujours affiché
|
||||
- le moral est indiqué avant l'icone d'appel au moral
|
||||
|
||||
## v11.0.27 - Khrachtchoum le méticuleux
|
||||
- le tooltip dans les TMR reste visible si on ne bouge pas la souris
|
||||
- le surencombrement n'affecte QUE les actions physiques
|
||||
- on peut de nouveau fabriquer une potion depuis la fenêtre d'édition de l'herbe
|
||||
- si les TMR sont minimisées alors qu'une action est requise, elles sont bien réaffichées lorsque l'action est faite
|
||||
|
||||
## v11.0.26 - le crépuscule de Khrachtchoum
|
||||
- gestion correcte des TMRs
|
||||
- les TMRs ne sont jamais minimisées (par le système) quand le haut-rêvant est en demi-rêve
|
||||
- lorsqu'une fenêtre liée aux demi-rêve est affichée, cliquer sur les TMRs n'a pas d'effet
|
||||
- les lancers de sorts et lectures de signes sont affichées en premier plan
|
||||
- Les effets qui ouvrent une fenêtre sont bien affichés en premier plan
|
||||
- en cas de rencontre suivie de maîtrises/conquêtes, les fenêtres s'enchaînent
|
||||
- Le drag&drop vers la barre de macro est corrigé
|
||||
- pour les créatures, possibilités d'avoir les attaques ou autres compétences
|
||||
- pour les personnages, les macros sont créées:
|
||||
- pour les compétences
|
||||
- pour le corps à corps, trois macros sont créées: compétence, pugilat, empoignade
|
||||
- pour les armes
|
||||
- deux macros sont créées pour les armes à 1/2 mains
|
||||
- deux macros sont créées pour les armes de mélée et lancer
|
||||
- 4 macros si votre arbalête se lance, tire, et se manie à 1 ou 2 mains...
|
||||
- les jets de compétences d'attaque des créatures fonctionnent de nouveau
|
||||
|
||||
## v11.0.25 - la vision du rêve de Khrachtchoum
|
||||
- Les TMRs restent affichées tant que le Haut-rêvant est en demi-rêve
|
||||
|
||||
## v11.0.24 - les couleurs de Khrachtchoum
|
||||
- nouvelle carte des TMRs
|
||||
|
||||
## v11.0.23 - la lumière de Khrachtchoum
|
||||
- ajustement automatique de la luminosité selon l'heure pour les scènes:
|
||||
- avec une vision des tokens (sinon: ce n'est pas une scène de carte pour tokens)
|
||||
- avec illumination globale (correspondant à une illumination extérieure)
|
||||
- quand lampe "allumée" dans la fenêtre du calendrier
|
||||
|
||||
## v11.0.22 - les automatismes de Khrachtchoum le Problémeux
|
||||
- Macro pour attaquer avec les compétences de créatures
|
||||
|
||||
## v11.0.20
|
||||
- Macro pour attaquer avec les armes des personnages
|
||||
|
||||
## v11.0.17
|
||||
- Fix: les actions de commerce ne s'appliquait pas bien aux personnages des tokens non liés
|
||||
|
||||
## v11.0.15 - L'apprentissage de Khrachtchoum
|
||||
- Fix: l'expérience ne s'appliquait plus sur certaines réussites particulières (régression depuis la 11.0.7)
|
||||
|
||||
## v11.0.14 - Les pincettes de Khrachtchoum le Problémeux
|
||||
- Correction du calcul de la place restante lors de l'ajout dans un conteneur
|
||||
|
||||
## v11.0.13 - La multiplication de l'eau de Khrachtchoum le Problémeux
|
||||
- Correction de la vente depuis un commerce ayant des quantités illimitées
|
||||
|
||||
## v11.0.12 - Les poids de la mesure de Khrachtchoum le Problémeux
|
||||
- Correction des malus de surencombrement
|
||||
- Le malus armure est correctement affiché dans l'onglet des caractéristiques
|
||||
- Correction d'orthographe et amélioration des messages des oeuvres d'art
|
||||
|
||||
## v11.0.11 - Les bleus de Khrachtchoum le Problémeux
|
||||
- si le gardien configure le sommeil, les joueurs sont notifiés que chateau dormant vient de passer
|
||||
- possibilité de créer des armes et des compétences de créatures non-mortelles.
|
||||
|
||||
## v11.0.10 - Les Songes de Khrachtchoum le Problémeux
|
||||
- on peut de nouveau se déplacer dans les TMRs d'un clic sur la case à atteindre
|
||||
- Lire un livre depuis l'inventaire permet de nouveau de faire un jet de la tâche
|
||||
créée au lieu de créer toujours une nouvelle tâche
|
||||
- La sélection des TMR pour la création de signes draconiques ne cause plus d'erreurs
|
||||
- la récupération d'endurance en cas d'insomnie est limitée à la moitié
|
||||
- le résultat du sommeil lors d'un rêve de dragon à la première heure s'affiche normalement
|
||||
- lorsque le gardien gère la durée des nuits, en cas de rêve de dragon,
|
||||
les heures dormies sont déduites des heures restant à dormir
|
||||
|
||||
## v11.0.9 - Les Souvenirs de Khrachtchoum le Problémeux
|
||||
- mode de saisie de l'archétype en vue détaillée
|
||||
- création une nouvelle incarnation depuis l'archétype
|
||||
- réorganisation de la fenêtre de sélection des règles optionnelles
|
||||
- correction de l'affichage du type dans les fenêtres d'objets
|
||||
|
||||
## v11.0.8 - la poigne de Sémolosse
|
||||
- lien vers le changelog
|
||||
- organisation des compendiums du système
|
||||
- correction de l'empoignade
|
||||
- les items d'empoignade sont ajoutés par le MJ quand nécessaire
|
||||
- seul le joueur propriétaire du personnage peut effectuer ses choix et actions d'empoignade
|
||||
- les caractéristiques du défenseur sont utilisées pour la défense
|
||||
- la difficulté d'attaque est imposée au défenseur
|
||||
- les attaques particulières sont en finesse (p133)
|
||||
- on peut entraîner au sol dès 2 points d'empoignade
|
||||
- les actions liée à l'immobilisation sont proposées en fin de round
|
||||
|
||||
# v11.0.7
|
||||
|
||||
- les créatures ont maintenant le droit d'avoir des compétences de tir, lancer, mêlée, armes naturelles, parade.
|
||||
- les créatures armées utilisent la bonne phase d'initiative
|
||||
- correction des possessions
|
||||
- la difficulté de la défense est imposée par l'attaque
|
||||
- une attaque particulière de possession est en finesse
|
||||
- le rêve actuel des personnages est bien utilisé
|
||||
- correction des achats par le MJ sans acteur sélectionné
|
||||
|
||||
Cf branche v10 pour l'historique des versions 10
|
||||
|
||||
- On peut de nouveau ouvrir les conteneurs dans une fenêtre séparée
|
||||
- Les jets de volontés d'éthylisme calculent correctement la difficulté liée au moral (ie: 0 au lieu de -22)
|
||||
- si le journal de chronologie est supprimée, on peut en choisir un autre
|
||||
- la taille du calendrier est ajustée pour éviter une présentation bancale quand le nom du mois est court
|
||||
|
61
dev-notes.md
@ -1,61 +0,0 @@
|
||||
# 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 — Aujourd’hui à 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
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 11 KiB |
BIN
icons/empoignade.webp
Normal file
After Width: | Height: | Size: 5.4 KiB |
4
icons/heures/.directory
Normal file
@ -0,0 +1,4 @@
|
||||
[Dolphin]
|
||||
Timestamp=2024,5,29,20,57,41.954
|
||||
Version=4
|
||||
VisibleRoles=Details_text,Details_size,Details_modificationtime,Details_creationtime,CustomizedDetails
|
BIN
icons/humanoides/humain.webp
Normal file
After Width: | Height: | Size: 6.3 KiB |
191
icons/tmr/attache.svg
Normal file
@ -0,0 +1,191 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
style="height: 512px; width: 512px;"
|
||||
version="1.1"
|
||||
id="svg52"
|
||||
sodipodi:docname="attache.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata56">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1769"
|
||||
inkscape:window-height="1333"
|
||||
id="namedview54"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.4355469"
|
||||
inkscape:cx="256"
|
||||
inkscape:cy="256"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg52" />
|
||||
<defs
|
||||
id="defs46">
|
||||
<filter
|
||||
id="shadow-1"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(248, 231, 28, 1)"
|
||||
result="flood"
|
||||
id="feFlood2" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite4" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="40"
|
||||
result="blur"
|
||||
id="feGaussianBlur6" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="0"
|
||||
result="offset"
|
||||
id="feOffset8" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite10" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-3"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(248, 231, 28, 1)"
|
||||
result="flood"
|
||||
id="feFlood13" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite15" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="40"
|
||||
result="blur"
|
||||
id="feGaussianBlur17" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="0"
|
||||
result="offset"
|
||||
id="feOffset19" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite21" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-6"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood24" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite26" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur28" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset30" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite32" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-7"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood35" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite37" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur39" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset41" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite43" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g
|
||||
class=""
|
||||
id="g50"
|
||||
style="stroke:#000000;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;fill:#7db27d;fill-opacity:1">
|
||||
<path
|
||||
d="m 90.53,23 c -18.345,0 -36.688,7.002 -50.686,21 -27.996,27.996 -27.994,73.38 0,101.375 21.776,21.776 54.08,26.603 80.53,14.5 l 53.69,53.688 c -21.425,19.696 -44,38.257 -67.44,55.937 l 30.126,30.125 c 18.734,-22.545 37.953,-44.474 57.844,-65.53 L 364.188,403.688 C 312.343,444.132 243.322,457.526 171.375,446.25 L 173,424.906 72.47,404.47 l 95.405,88.405 1.97,-26 c 86.593,36.97 177.603,34.61 241.343,-11.75 l 63.062,21.313 -21.47,-63.594 c 44.61,-63.62 46.408,-153.412 9.908,-238.875 l 26.03,-1.97 -88.406,-95.375 20.438,100.53 21.344,-1.624 c 11.278,71.983 -2.168,141.017 -42.656,192.876 L 229.656,198.656 c 21.075,-20.34 42.93,-39.665 65.78,-57.72 l -30.123,-30.124 c -17.015,24.154 -35.673,46.66 -55.688,67.813 l -53.97,-53.97 C 167.834,98.183 163.032,65.814 141.22,44 127.22,30.002 108.877,23 90.53,23 Z m 0,27.03 c 11.434,0.002 22.872,4.34 31.595,13.064 17.447,17.447 17.446,45.742 0,63.187 -17.446,17.447 -45.71,17.447 -63.156,0 -17.447,-17.444 -17.448,-45.74 0,-63.186 C 67.69,54.37 79.097,50.03 90.53,50.03 Z"
|
||||
fill="#8eff09"
|
||||
fill-opacity="1"
|
||||
transform="matrix(0.9,0,0,0.9,25.6,25.6)"
|
||||
filter="url(#shadow-1)"
|
||||
id="path48"
|
||||
style="stroke:#000000;stroke-width:11.11111111;stroke-miterlimit:4;stroke-dasharray:none;fill:#7db27d;fill-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.8 KiB |
159
icons/tmr/conquete.svg
Normal file
@ -0,0 +1,159 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
style="height: 512px; width: 512px;"
|
||||
version="1.1"
|
||||
id="svg41"
|
||||
sodipodi:docname="conquete.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata45">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2077"
|
||||
inkscape:window-height="1321"
|
||||
id="namedview43"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.4355469"
|
||||
inkscape:cx="256"
|
||||
inkscape:cy="256"
|
||||
inkscape:window-x="1573"
|
||||
inkscape:window-y="459"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg41" />
|
||||
<defs
|
||||
id="defs35">
|
||||
<filter
|
||||
id="shadow-1"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(248, 231, 28, 1)"
|
||||
result="flood"
|
||||
id="feFlood2" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite4" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="40"
|
||||
result="blur"
|
||||
id="feGaussianBlur6" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="0"
|
||||
result="offset"
|
||||
id="feOffset8" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite10" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-6"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood13" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite15" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur17" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset19" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite21" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-7"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood24" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite26" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur28" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset30" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite32" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g
|
||||
class=""
|
||||
id="g39"
|
||||
style="stroke:#000000;stroke-width:8;stroke-miterlimit:4;stroke-dasharray:none">
|
||||
<path
|
||||
d="m 27.084,18.248 c -44.987,128.23 116.066,259.672 287.412,362.826 -4.645,13.767 -5.585,27.628 -3.394,40.635 4.44,26.355 20.974,48.997 42.86,62.425 21.884,13.428 49.776,17.57 75.645,5.765 25.87,-11.804 48.69,-38.923 62.737,-84.654 l -17.865,-5.488 c -13,42.318 -32.806,64.094 -52.63,73.14 -19.825,9.047 -40.69,5.998 -58.116,-4.693 -17.425,-10.69 -30.75,-29.095 -34.205,-49.6 -3.455,-20.507 2.232,-43.318 24.677,-65.218 20.743,-20.24 32.068,-41.615 30.434,-61.24 l -18.622,1.552 c 0.74,8.89 -4.35,22.76 -16.684,37.486 C 222.057,230.8 73.838,128.622 27.084,18.248 Z m 458.05,0 C 451.34,98.03 364.527,173.53 270.93,247.166 c 19.492,15.878 39.56,31.622 59.195,45.012 110.756,-84.836 187.878,-180.243 155.01,-273.93 z M 127.58,292.146 c -1.634,19.626 9.69,41 30.434,61.24 22.445,21.9 28.132,44.712 24.677,65.218 -3.455,20.506 -16.78,38.91 -34.206,49.6 -17.425,10.692 -38.29,13.74 -58.115,4.694 -19.825,-9.046 -39.632,-30.822 -52.63,-73.14 l -17.865,5.488 c 14.046,45.73 36.867,72.85 62.736,84.654 25.87,11.805 53.763,7.663 75.648,-5.765 21.885,-13.428 38.42,-36.07 42.86,-62.426 2.19,-13.005 1.25,-26.863 -3.393,-40.628 13.986,-8.42 27.905,-17.022 41.648,-25.803 l -56.967,-39.387 c -6.55,5.103 -13.063,10.2 -19.52,15.293 C 150.55,316.46 145.46,302.59 146.2,293.7 l -18.622,-1.554 z m 18.1,73.614 c -26.1,8.6 -62.087,36.255 -77.104,60.324 4.948,8.63 10.393,15.223 16.05,20.14 25.846,-8.953 59.85,-37.406 74.733,-60.257 -3.007,-6.6 -7.454,-13.386 -13.68,-20.207 z m 220.863,0 c -6.225,6.822 -10.67,13.61 -13.68,20.21 14.886,22.85 48.89,51.3 74.736,60.255 5.656,-4.918 11.1,-11.51 16.05,-20.14 -15.018,-24.07 -51.004,-51.724 -77.105,-60.325 z"
|
||||
fill="#b41e00"
|
||||
fill-opacity="1"
|
||||
transform="matrix(0.9,0,0,0.9,25.6,25.6)"
|
||||
filter="url(#shadow-1)"
|
||||
id="path37"
|
||||
style="stroke:#000000;stroke-width:8.88888889;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.6 KiB |
191
icons/tmr/debordement.svg
Normal file
@ -0,0 +1,191 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
style="height: 256px; width: 256px;"
|
||||
version="1.1"
|
||||
id="svg52"
|
||||
sodipodi:docname="debordement.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata56">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2673"
|
||||
inkscape:window-height="1516"
|
||||
id="namedview54"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.4355469"
|
||||
inkscape:cx="256"
|
||||
inkscape:cy="256"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg52" />
|
||||
<defs
|
||||
id="defs46">
|
||||
<filter
|
||||
id="shadow-1"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(255, 255, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood2" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite4" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="10"
|
||||
result="blur"
|
||||
id="feGaussianBlur6" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="10"
|
||||
result="offset"
|
||||
id="feOffset8" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite10" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-3"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(248, 231, 28, 1)"
|
||||
result="flood"
|
||||
id="feFlood13" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite15" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="40"
|
||||
result="blur"
|
||||
id="feGaussianBlur17" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="0"
|
||||
result="offset"
|
||||
id="feOffset19" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite21" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-6"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood24" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite26" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur28" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset30" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite32" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-7"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood35" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite37" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur39" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset41" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite43" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g
|
||||
class=""
|
||||
id="g50"
|
||||
style="stroke:#5959b2;stroke-width:7;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">
|
||||
<path
|
||||
d="m 400.9,104.8 c -12,30 -41,47.9 -99.7,43.9 -13.7,-1.8 -27.6,-4.1 -41.6,-6.7 C 140.5,104.8 23.36,104.8 23.36,179.2 56.84,142 141.1,148.4 248.4,175.2 c 116.8,29.2 241.8,41.2 241.8,-51.8 -18.4,19.3 -53.4,28.6 -96.6,30.4 10,-10.4 12.5,-26.7 7.3,-49 z M 147,187.5 c -70.75,-0.3 -123.64,16.1 -123.64,66.1 33.48,-37.2 117.74,-34.8 225.04,-8 116.8,29.2 241.8,45.2 241.8,-47.8 -35.4,37.2 -130.2,39.6 -230.6,8 -37.7,-11.9 -78,-18.2 -112.6,-18.3 z m -23.9,69.6 C 64.66,256.9 23.36,272.7 23.36,328 56.84,290.8 145.7,283.7 248.4,309.4 c 121,30.2 241.8,37.2 241.8,-37.2 -35.4,37.2 -132.1,22.6 -230.6,4 -48.4,-7.5 -96.5,-19.1 -136.5,-19.1 z m 0,74.3 c -58.44,-0.1 -99.74,15.8 -99.74,71 19.03,-21.1 55.52,-30.3 102.54,-30.8 -10.4,10.4 -12.9,26.9 -7.7,49.4 13.9,-34.8 52,-51.8 130.3,-37.2 122.6,22.8 241.7,37.2 241.7,-37.2 -35.4,37.2 -132.1,18.6 -230.6,0 -48.4,-7.6 -96.5,-15.1 -136.5,-15.2 z"
|
||||
fill="#48baff"
|
||||
fill-opacity="1"
|
||||
transform="matrix(0.9,0,0,0.9,25.6,25.6)"
|
||||
filter="url(#shadow-1)"
|
||||
id="path48"
|
||||
style="stroke:#5959b2;stroke-width:7.77777778;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.6 KiB |
127
icons/tmr/demi-reve.svg
Normal file
@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
style="height: 512px; width: 512px;"
|
||||
version="1.1"
|
||||
id="svg30"
|
||||
sodipodi:docname="demi-reve.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata34">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2513"
|
||||
inkscape:window-height="1633"
|
||||
id="namedview32"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.2094112"
|
||||
inkscape:cx="256"
|
||||
inkscape:cy="256"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg30"
|
||||
inkscape:document-rotation="0" />
|
||||
<defs
|
||||
id="defs24">
|
||||
<filter
|
||||
id="shadow-6"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood2" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite4" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur6" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset8" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite10" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-7"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood13" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite15" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur17" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset19" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite21" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g
|
||||
class=""
|
||||
transform="translate(-2.1627108,-0.3)"
|
||||
id="g28"
|
||||
style="stroke:#000080;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none">
|
||||
<path
|
||||
d="m 342.5,17.9 c -3.1,11.63 -2.2,21.56 -23.8,25.11 20.3,-2.7 22.3,9.58 24.8,21.49 -2.8,1.94 -5.5,4.11 -8.1,6.49 -21.9,20.84 -33,41.11 -49,61.61 -6.3,1.2 5.3,-53.52 31.1,-79.87 C 225.1,40.92 207.6,268.4 236.4,275 184.7,293.4 163.8,176.7 177,117.7 c -37.1,3.9 -62,39.8 -67.9,60 2.8,27.1 6.1,55.1 38.7,80.9 -32.1,3.6 -42,-27.8 -55.31,-54 -78.59,104.9 105.91,106.8 136.01,94.5 -93,70.5 -149.62,52.3 -196.77,39 -40.48,85.1 61.46,56 107.57,35.7 -18.4,30.7 -72.25,37.6 -88.92,41 61.62,51.3 174.42,-67 200.02,-106.5 2.5,65.7 -74.3,134.4 -122.8,171.7 43.6,2.2 83.2,-17.9 102.4,-55.5 0,10.1 -4.1,22.6 -9.6,35.8 15,-2.1 39.6,-6.2 48.8,-24.2 25,-54.1 37.8,-93.1 15.3,-138.2 29.9,33.5 63.6,65.3 58.4,114.5 26.9,-15.6 48.8,-33.6 24.7,-60.1 14.1,1.4 23.6,7.7 32.8,13.7 13.9,-2.8 34.4,-19.9 33.7,-33 -31.6,-29.8 -83.4,-43.7 -133.8,-55.9 72.1,-19.8 136.9,-10.1 175.6,5.6 5,-11.7 9.4,-29.6 5.9,-41.9 -16.4,-9.7 -62.7,-7.8 -83.3,-5.6 17.7,-15.7 56.8,-21.1 81.3,-21.2 -2,-67.7 -162.6,27.8 -182.2,42.8 32.7,-59.1 123.2,-112.7 178.7,-121.1 -13.2,-31.1 -37.2,-34 -64.3,-22.4 2.4,-9.5 6.7,-17.49 23.4,-15.29 -21.6,-3.51 -20.7,-13.44 -23.8,-25.07 -2.4,13.55 -4.1,17.11 -19.4,26.67 14.3,-2.17 16.4,6.69 17.4,14.69 -53.5,24.4 -117.8,102.8 -135.1,132.5 -22.1,-24 51,-121.5 107.7,-187.46 -3.1,-9.48 -21.8,-6.31 -38.2,4.81 1.1,-8.63 0.7,-22.16 17.9,-19.54 -15.3,-9.6 -17,-13.16 -19.4,-26.71 z m -166.3,0.3 c 5.4,10.73 12.7,17.53 -1,34.56 13.8,-16.07 23.7,-7.13 33.9,0.22 -4.6,-7.19 -16.3,-17.67 -0.7,-27.86 -17.8,3.09 -21.4,1.57 -32.2,-6.92 z M 47.71,26.61 C 44.63,38.24 45.58,48.17 23.95,51.66 44.97,48.92 46.34,62.21 49.01,74.47 50.44,66.04 48.73,50.5 67.15,53.31 51.88,43.72 50.17,40.16 47.71,26.61 Z m 419.39,5.5 c 1.6,10.83 1.3,13.93 -7.8,25.07 13.1,-6.8 15.9,5.39 19.1,11.38 C 477.2,58.59 475,48.2 491.5,44.92 474.3,47.79 472.4,40.07 467.1,32.11 Z M 125.3,84.28 c -0.6,18.02 -12,17.32 -22.7,17.92 7,2.4 20.3,3 15.3,18.2 10.2,-11.6 13.3,-12.5 25.2,-12.6 -9.4,-4.3 -17.8,-4.9 -17.8,-23.52 z M 71.21,153.9 c -8.61,8.5 -12.85,17.5 -33.24,9.6 19.47,8.3 13.98,20.4 10.08,32.4 5.46,-6.6 11.9,-20.9 26.35,-9.1 -8.38,-16 -8.02,-19.9 -3.19,-32.9 z M 453.9,282.7 c -2.4,8.9 -1.7,16.5 -18.2,19.2 16,-2.1 17.1,8.1 19.2,17.5 1.1,-6.5 -0.2,-18.4 13.8,-16.3 -11.7,-7.3 -13,-10 -14.8,-20.4 z M 69.25,293.8 c -12.82,12.7 -16.72,13.5 -30.41,12.7 10.55,5.7 20.39,7.1 18.72,29 2.3,-21.1 15.46,-19.4 28.05,-19.1 -7.83,-3.3 -23.4,-5.3 -16.36,-22.6 z m 394.55,50.7 c 3.1,11.6 8.9,19.7 -8,33.6 16.8,-12.9 24.6,-2.2 33.2,7.1 -3.1,-8 -12.4,-20.6 4.9,-27.4 -18,-0.5 -21.3,-2.8 -30.1,-13.3 z m -139.2,72.1 c -2.7,12.3 -4.1,25.5 -25.1,22.8 21.6,3.5 20.7,13.4 23.8,25 2.4,-13.5 4.1,-17.1 19.4,-26.6 C 324.3,440.6 326,425 324.6,416.6 Z M 83.9,438.2 c -2.83,16 -4.84,20.2 -22.86,31.5 21.68,-3.3 19.67,15.1 21.33,25 3.19,-14.5 4.84,-30.1 29.63,-26.9 -25.5,-4.2 -24.43,-15.9 -28.1,-29.6 z m 366.2,11.4 c -7.3,9.6 -10.2,19.1 -31.5,14.2 20.4,5.4 16.8,18.1 14.6,30.6 4.5,-7.3 8.8,-22.4 24.8,-12.8 -10.6,-14.6 -10.8,-18.6 -7.9,-32 z"
|
||||
fill="#ffffff"
|
||||
fill-opacity="1"
|
||||
id="path26"
|
||||
style="stroke:#000080;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.1 KiB |
55
icons/tmr/desorientation.svg
Normal file
@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
style="height: 512px; width: 512px;"
|
||||
version="1.1"
|
||||
id="svg6"
|
||||
sodipodi:docname="desorientation.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata12">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1599"
|
||||
inkscape:window-height="932"
|
||||
id="namedview8"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.3119567"
|
||||
inkscape:cx="256"
|
||||
inkscape:cy="256"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg6" />
|
||||
<path
|
||||
d="m 203.97,23 -18.032,4.844 11.656,43.468 c -25.837,8.076 -50.32,21.653 -71.594,40.75 l -31.47,-31.468 -13.218,13.22 31.376,31.374 c -19.467,21.125 -33.414,45.53 -41.813,71.343 l -42.313,-11.343 -4.843,18.063 42.25,11.313 c -6.057,27.3 -6.157,55.656 -0.345,83 l -41.904,11.216 4.843,18.064 41.812,-11.22 c 6.693,21.225 17.114,41.525 31.25,59.876 l -29.97,52.688 -16.81,29.593 29.56,-16.842 52.657,-29.97 c 18.41,14.216 38.784,24.69 60.094,31.407 l -11.22,41.844 18.033,4.81 11.218,-41.905 c 27.345,5.808 55.698,5.686 83,-0.375 l 11.312,42.28 18.063,-4.81 -11.344,-42.376 c 25.812,-8.4 50.217,-22.315 71.342,-41.78 l 31.375,31.373 13.22,-13.218 -31.47,-31.47 c 19.09,-21.266 32.643,-45.738 40.72,-71.563 l 43.53,11.657 4.813,-18.063 -43.625,-11.686 c 5.68,-27.044 5.576,-55.06 -0.344,-82.063 l 43.97,-11.78 -4.813,-18.063 L 440.908,197 c -6.73,-20.866 -17.08,-40.79 -31.032,-58.844 l 29.97,-52.656 16.842,-29.563 -29.593,16.844 -52.656,29.97 C 356.441,88.876 336.565,78.553 315.782,71.845 l 11.783,-44 L 309.5,23 297.72,66.97 c -27,-5.925 -55.02,-6.05 -82.064,-0.376 z m 201.56,85 -108.28,190.313 -0.75,0.437 -40.844,-40.875 -148.72,148.72 -2.186,1.25 109.125,-191.75 41.78,41.78 L 405.532,108 Z m -149.686,10.594 c 21.858,0 43.717,5.166 63.594,15.47 l -116.625,66.342 -2.22,1.28 -1.28,2.22 -66.25,116.406 c -26.942,-52.04 -18.616,-117.603 25.03,-161.25 26.99,-26.988 62.38,-40.468 97.75,-40.468 z m 122.72,74.594 c 26.994,52.054 18.67,117.672 -25.002,161.343 -43.66,43.662 -109.263,52.005 -161.312,25.033 l 116.438,-66.282 2.25,-1.25 1.25,-2.25 66.375,-116.592 z"
|
||||
fill="#d0021b"
|
||||
fill-opacity="1"
|
||||
id="path2"
|
||||
style="fill:#401060;fill-opacity:1" />
|
||||
</svg>
|
After Width: | Height: | Size: 3.1 KiB |
193
icons/tmr/fermeture.svg
Normal file
@ -0,0 +1,193 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
style="height: 512px; width: 512px;"
|
||||
version="1.1"
|
||||
id="svg52"
|
||||
sodipodi:docname="fermeture.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata56">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2665"
|
||||
inkscape:window-height="1441"
|
||||
id="namedview54"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.5990661"
|
||||
inkscape:cx="256"
|
||||
inkscape:cy="256"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg52"
|
||||
inkscape:document-rotation="0" />
|
||||
<defs
|
||||
id="defs46">
|
||||
<filter
|
||||
id="shadow-1"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(248, 231, 28, 1)"
|
||||
result="flood"
|
||||
id="feFlood2" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite4" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="40"
|
||||
result="blur"
|
||||
id="feGaussianBlur6" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="0"
|
||||
result="offset"
|
||||
id="feOffset8" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite10" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-3"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(248, 231, 28, 1)"
|
||||
result="flood"
|
||||
id="feFlood13" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite15" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="40"
|
||||
result="blur"
|
||||
id="feGaussianBlur17" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="0"
|
||||
result="offset"
|
||||
id="feOffset19" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite21" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-6"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood24" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite26" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur28" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset30" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite32" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-7"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood35" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite37" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur39" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset41" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite43" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g
|
||||
class=""
|
||||
id="g50"
|
||||
transform="matrix(1.1287777,0,0,1.1287777,-32.967091,-40.026839)"
|
||||
style="stroke:#000000;stroke-width:4.42957014;stroke-miterlimit:4;stroke-dasharray:none">
|
||||
<path
|
||||
d="M 72.877,31.904 C 71.887,31.89 70.919,31.91 69.889,32.002 43.67,35.408 22.545,61.005 18,93.775 v 26.15 c 2.296,16.266 8.804,30.665 17.848,41.565 -6.58,1.237 -12.504,3.53 -17.848,6.717 v 23.813 c 22.983,0.386 43.265,14.03 57.31,34.318 C 89.56,246.92 98,274.598 98,305 98,335.402 89.56,363.08 75.31,383.662 61.266,403.95 40.984,417.592 18,417.98 v 8.577 L 23.03,494 H 30.7 L 138.904,332.176 140,304 c 0.732,-41.132 16.536,-59.598 32,-48 4.26,3.195 8.3,6.024 12.135,8.533 l 23.574,-35.258 c -21.607,-17.4 -59.103,-43.23 -90.68,-68.658 10.89,-13.647 17.894,-32.612 17.894,-53.627 C 134.924,65.494 108.478,32 76,32 74.88,31.964 73.867,31.918 72.877,31.904 Z m 366.246,0 c -0.99,0.014 -2.002,0.06 -3.123,0.096 -32.478,0 -58.924,33.494 -58.924,74.99 0,21.015 7.005,39.98 17.895,53.627 -31.577,25.43 -69.073,51.26 -90.68,68.658 l 23.577,35.258 A 232.03,232.03 0 0 0 340,256 c 15.464,-11.598 31.268,6.868 32,48 l 1.096,28.174 L 481.3,494 h 7.67 L 494,426.557 v -8.578 C 471.017,417.591 450.735,403.949 436.69,383.661 422.44,363.08 414,335.402 414,305 c 0,-30.402 8.44,-58.08 22.69,-78.662 14.045,-20.288 34.327,-33.932 57.31,-34.318 v -23.813 c -5.344,-3.187 -11.27,-5.48 -17.848,-6.717 9.044,-10.9 15.552,-25.3 17.848,-41.566 V 93.774 C 489.454,61.004 468.33,35.408 442.11,32.002 a 28.52,28.52 0 0 0 -2.987,-0.098 z m -290.365,14.854 40.068,110.215 47.34,-31.653 z m 214.484,0 -87.408,78.562 47.34,31.653 z M 230.25,150.93 213.625,162.047 435.588,494 h 24.057 z m 51.5,0 -14.922,22.316 12.03,17.99 19.517,-29.19 z M 18,210.018 v 189.964 c 15.993,-0.38 30.943,-9.855 42.512,-26.566 C 72.322,356.356 80,332.036 80,305 80,277.965 72.322,253.643 60.512,236.584 48.942,219.874 33.992,210.398 18,210.018 Z m 476,0 c -15.993,0.38 -30.943,9.855 -42.512,26.566 C 439.678,253.644 432,277.964 432,305 c 0,27.035 7.678,51.357 19.488,68.416 11.57,16.71 26.52,26.186 42.512,26.566 z M 233.145,223.62 52.355,494 H 76.412 L 245.174,241.61 Z M 134.748,439.14 98.066,494 h 34.55 z m 242.504,0 2.13,54.86 h 34.552 z"
|
||||
fill="#003fb2"
|
||||
fill-opacity="1"
|
||||
transform="matrix(0.9,0,0,0.9,25.6,25.6)"
|
||||
filter="url(#shadow-1)"
|
||||
id="path48"
|
||||
style="stroke:#000000;stroke-width:4.92174461;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 44 KiB |
187
icons/tmr/maitrisee.svg
Normal file
@ -0,0 +1,187 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
style="height: 512px; width: 512px;"
|
||||
version="1.1"
|
||||
id="svg56"
|
||||
sodipodi:docname="maitrisee.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata60">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2352"
|
||||
inkscape:window-height="1016"
|
||||
id="namedview58"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.4355469"
|
||||
inkscape:cx="256"
|
||||
inkscape:cy="256"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg56" />
|
||||
<defs
|
||||
id="defs46">
|
||||
<filter
|
||||
id="shadow-1"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(248, 231, 28, 1)"
|
||||
result="flood"
|
||||
id="feFlood2" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite4" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="40"
|
||||
result="blur"
|
||||
id="feGaussianBlur6" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="0"
|
||||
result="offset"
|
||||
id="feOffset8" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite10" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-3"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(248, 231, 28, 1)"
|
||||
result="flood"
|
||||
id="feFlood13" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite15" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="40"
|
||||
result="blur"
|
||||
id="feGaussianBlur17" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="0"
|
||||
result="offset"
|
||||
id="feOffset19" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite21" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-6"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood24" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite26" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur28" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset30" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite32" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-7"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood35" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite37" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur39" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset41" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite43" />
|
||||
</filter>
|
||||
</defs>
|
||||
<path
|
||||
d="m 16,256 v 240 h 48 c 64,-160 320,-160 384,0 h 48 V 256 h -48 v 64 h -60 v -64 h -48 v 64 h -60 v -64 h -48 v 64 h -60 v -64 h -48 v 64 H 64 v -64 z"
|
||||
class="selected"
|
||||
fill="#087505"
|
||||
fill-opacity="1"
|
||||
filter="url(#shadow-3)"
|
||||
id="path50"
|
||||
style="fill:#7db27d;fill-opacity:1;stroke:#000000;stroke-width:11.11111111;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
transform="matrix(0.9,0,0,0.9,25.6,25.6)" />
|
||||
</svg>
|
After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 25 KiB |
159
icons/tmr/pelerinage.svg
Normal file
@ -0,0 +1,159 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
style="height: 512px; width: 512px;"
|
||||
version="1.1"
|
||||
id="svg41"
|
||||
sodipodi:docname="pelerinage.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata45">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2530"
|
||||
inkscape:window-height="1154"
|
||||
id="namedview43"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.4355469"
|
||||
inkscape:cx="256"
|
||||
inkscape:cy="256"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg41" />
|
||||
<defs
|
||||
id="defs35">
|
||||
<filter
|
||||
id="shadow-1"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(248, 231, 28, 1)"
|
||||
result="flood"
|
||||
id="feFlood2" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite4" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="40"
|
||||
result="blur"
|
||||
id="feGaussianBlur6" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="0"
|
||||
result="offset"
|
||||
id="feOffset8" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite10" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-6"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood13" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite15" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur17" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset19" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite21" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-7"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood24" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite26" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur28" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset30" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite32" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g
|
||||
class=""
|
||||
id="g39"
|
||||
style="stroke:#000000;stroke-width:8;stroke-miterlimit:4;stroke-dasharray:none">
|
||||
<path
|
||||
d="m 259.844,73.406 1.625,214.47 -18.69,0.155 -1.655,-214.342 C 206.358,75.24 172.012,82.588 141,95.78 c 36.116,61.6 59.493,126.474 75.813,196.5 l -18.22,4.25 C 182.46,227.29 159.504,163.924 124,103.78 86.984,122.97 56.014,151.27 36.844,188.75 94.728,213.41 141.97,256.61 177.781,307.438 l -15.28,10.75 C 128.217,269.528 83.409,228.86 29.221,205.844 c -8.57,22.082 -13.345,46.943 -13.345,74.594 95.028,17.855 145.516,75.937 151.406,92 3.752,10.228 -27.905,21.074 -27.905,38.156 0,12.34 25.52,20.537 59.668,24.67 -3.846,-4.94 -7.694,-10.374 -11.59,-16.31 l 15.625,-10.255 c 9.802,14.937 18.996,25.865 27.354,32.73 8.358,6.864 15.493,9.632 22.423,9.68 13.862,0.094 31.592,-12.316 53.723,-42.776 l 15.12,10.984 c -4.31,5.93 -8.553,11.385 -12.76,16.35 36.362,-4.006 64.125,-12.375 64.125,-25.074 0,-17.92 -35.487,-28.412 -33.72,-39.97 2.31,-15.09 55.528,-74.91 156.626,-90.187 0,-28.807 -5.284,-54.622 -14.72,-77.437 -57.322,22.41 -104.478,64.46 -140.22,115.188 l -15.28,-10.75 c 37.145,-52.72 86.607,-97.216 147.47,-121.344 -20.457,-37.87 -53.207,-66.233 -92.064,-85.03 -36.426,60.947 -59.84,125.186 -76.22,195.467 l -18.186,-4.25 C 303.274,221.387 327.029,155.78 363.907,93.5 331.487,80.665 295.741,73.95 259.845,73.406 Z"
|
||||
fill="#b41e00"
|
||||
fill-opacity="1"
|
||||
transform="matrix(0.9,0,0,0.9,25.6,25.6)"
|
||||
filter="url(#shadow-1)"
|
||||
id="path37"
|
||||
style="stroke:#000000;stroke-width:8.88888889;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.2 KiB |
191
icons/tmr/periple.svg
Normal file
@ -0,0 +1,191 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
style="height: 512px; width: 512px;"
|
||||
version="1.1"
|
||||
id="svg52"
|
||||
sodipodi:docname="periple.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata56">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2760"
|
||||
inkscape:window-height="1358"
|
||||
id="namedview54"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.4355469"
|
||||
inkscape:cx="256"
|
||||
inkscape:cy="256"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg52" />
|
||||
<defs
|
||||
id="defs46">
|
||||
<filter
|
||||
id="shadow-1"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(248, 231, 28, 1)"
|
||||
result="flood"
|
||||
id="feFlood2" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite4" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="40"
|
||||
result="blur"
|
||||
id="feGaussianBlur6" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="0"
|
||||
result="offset"
|
||||
id="feOffset8" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite10" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-3"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(248, 231, 28, 1)"
|
||||
result="flood"
|
||||
id="feFlood13" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite15" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="40"
|
||||
result="blur"
|
||||
id="feGaussianBlur17" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="0"
|
||||
result="offset"
|
||||
id="feOffset19" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite21" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-6"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood24" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite26" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur28" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset30" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite32" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-7"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood35" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite37" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur39" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset41" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite43" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g
|
||||
class=""
|
||||
id="g50"
|
||||
style="stroke:#000000;stroke-width:8;stroke-miterlimit:4;stroke-dasharray:none">
|
||||
<path
|
||||
d="M 149.9,27.2 34.25,56.74 V 133.5 L 157.8,93.85 204.5,49.18 Z m 132.8,57 c -7.4,0.18 -10.1,1.88 0.9,7.13 C 346.9,121.6 441.7,206.8 391.3,216.9 232.2,249 130.4,292.3 48.51,390.8 25.42,418.6 18,494.8 18,494.8 h 432.6 c 0,0 -139,-21.1 -147.8,-75.7 C 287.9,326.9 497.3,316.4 499.3,219.2 500.2,176 411,94.21 314.9,86.68 309.3,86.24 292.2,83.97 282.7,84.2 Z m -163.5,40.9 -32.69,10.5 v 122.2 l 35.99,-10 z"
|
||||
fill="#b41e00"
|
||||
fill-opacity="1"
|
||||
transform="matrix(0.9,0,0,0.9,25.6,25.6)"
|
||||
filter="url(#shadow-1)"
|
||||
id="path48"
|
||||
style="stroke:#000000;stroke-width:8.88888889;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.1 KiB |
132
icons/tmr/present.svg
Normal file
@ -0,0 +1,132 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
style="height: 512px; width: 512px;"
|
||||
version="1.1"
|
||||
id="svg32"
|
||||
sodipodi:docname="present.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata36">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2323"
|
||||
inkscape:window-height="1657"
|
||||
id="namedview34"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.0301699"
|
||||
inkscape:cx="290.19906"
|
||||
inkscape:cy="295.26229"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg32" />
|
||||
<defs
|
||||
id="defs24">
|
||||
<filter
|
||||
id="shadow-6"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood2" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite4" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur6" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset8" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite10" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-7"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood13" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite15" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur17" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset19" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite21" />
|
||||
</filter>
|
||||
</defs>
|
||||
<path
|
||||
d="M0 0h512v512H0z"
|
||||
fill="#4a4a4a"
|
||||
fill-opacity="0.5"
|
||||
id="path26"
|
||||
style="fill:none" />
|
||||
<g
|
||||
class=""
|
||||
transform="translate(1,-1)"
|
||||
id="g30"
|
||||
style="stroke:#000000;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;fill:#7db27d;fill-opacity:1">
|
||||
<path
|
||||
d="M149.518 78.38c-6.55.117-12.45 1.736-17.35 4.91-7.465 4.84-11.765 12.904-13.063 21.34-2.595 16.874 4.747 36.355 19.862 52.31C154.08 172.893 177.643 185 208 185h2.438l-9.118-18.234c-22.194-1.554-38.46-10.777-49.287-22.205-11.885-12.545-16.543-28.064-15.138-37.19.702-4.564 2.402-7.25 5.062-8.974 2.66-1.724 7.113-2.875 14.756-1.326 13.078 2.65 34.233 13.948 62.205 39.284L220.27 135h23.408c-35.31-34.8-62.215-51.278-83.39-55.57-2.715-.55-5.363-.887-7.925-1.006-.96-.045-1.91-.06-2.845-.043zm212.964 0c-.935-.016-1.885 0-2.845.044-2.562.12-5.21.455-7.924 1.006-21.176 4.292-48.082 20.77-83.39 55.57h23.406l1.352 1.354c27.972-25.336 49.127-36.633 62.205-39.284 7.643-1.55 12.096-.398 14.756 1.326 2.66 1.725 4.36 4.41 5.062 8.973 1.405 9.126-3.253 24.645-15.138 37.19-10.827 11.43-27.093 20.652-49.287 22.206L301.562 185H304c30.357 0 53.92-12.106 69.033-28.06 15.115-15.955 22.457-35.436 19.862-52.31-1.298-8.436-5.598-16.5-13.063-21.34-4.9-3.174-10.8-4.793-17.35-4.91zM227.73 153l-8.78 8.777L229.564 183h52.875l10.61-21.223-8.777-8.777h-56.54zM73 201v46h142v-46H73zm160 0v270h46V201h-46zm64 0v46h142v-46H297zm-192 64v206h110V265H105zm192 0v206h110V265H297z"
|
||||
fill="#ffffff"
|
||||
fill-opacity="1"
|
||||
id="path28"
|
||||
style="stroke:#000000;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;fill:#7db27d;fill-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.5 KiB |
159
icons/tmr/rencontre.svg
Normal file
@ -0,0 +1,159 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
style="height: 512px; width: 512px;"
|
||||
version="1.1"
|
||||
id="svg41"
|
||||
sodipodi:docname="rencontre.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata45">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1683"
|
||||
inkscape:window-height="1292"
|
||||
id="namedview43"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.4355469"
|
||||
inkscape:cx="256"
|
||||
inkscape:cy="256"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg41" />
|
||||
<defs
|
||||
id="defs35">
|
||||
<filter
|
||||
id="shadow-1"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(248, 231, 28, 1)"
|
||||
result="flood"
|
||||
id="feFlood2" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite4" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="40"
|
||||
result="blur"
|
||||
id="feGaussianBlur6" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="0"
|
||||
result="offset"
|
||||
id="feOffset8" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite10" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-6"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood13" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite15" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur17" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset19" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite21" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-7"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood24" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite26" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur28" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset30" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite32" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g
|
||||
class=""
|
||||
id="g39"
|
||||
style="stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none">
|
||||
<path
|
||||
d="m 324.97,17.54 c 0.03,0.034 0.057,0.07 0.087,0.106 l -34.924,32.428 36.904,-3.752 -15.396,30.12 38.048,-16.075 c 26.147,69.965 0.623,154.277 -52.555,166.262 -6.554,-25.37 -34.13,-37.945 -36.055,-57.382 0.303,0.093 0.604,0.187 0.912,0.27 4.833,1.295 9.736,1.183 14.274,-0.07 l 25.138,22.89 20.653,-16.377 c -7.363,2.836 -28.588,-1.402 -33.25,-13.923 3.154,-3.24 5.55,-7.284 6.793,-11.922 0.485,-1.813 0.757,-3.635 0.86,-5.445 l 11.524,22.777 5.22,-16.94 c 7.625,5.575 12.474,13.605 11.49,21.136 l 16.673,-29.4 -72.14,-29.56 -58.057,-48.03 17.1,31.25 -48.206,-19.753 35.14,31.237 c -40.602,28.158 -22.085,85.04 -1.796,119.29 -57.5,-9.685 -103.128,-77.435 -95.763,-145.03 l 49.21,-21.366 -31.08,-5.14 29.207,-33.417 -32.015,11.54 c 0.037,-0.067 0.07,-0.135 0.107,-0.202 -168.36,66.33 -116.413,367 -63.728,417.99 -0.19,-1.317 -0.364,-2.58 -0.54,-3.855 C 53.883,390.953 48.43,321.573 51.305,256.667 54.325,188.43 66.139,125.507 88.099,87.145 l 16.22,9.283 c -18.894,33.008 -31.4,94.563 -34.345,161.064 -1.942,43.86 0.106,90.022 6.275,132.082 6.124,1.892 15.046,9.615 27.295,23.24 -4.818,-13.35 -6.78,-26.5 -6.482,-38.28 20.286,41.665 67.34,69.234 104.633,62.308 22.444,-4.17 41.803,-12.73 57.81,-24.475 l 7.31,15.418 c -20.068,5.036 -22.807,32.635 -14.737,55.112 1.748,-19.882 11.36,-29.794 21.73,-32.303 -6.598,15.867 -4.698,30.623 -3.117,44.158 10.15,-12.147 21.47,-23.793 23.628,-39.354 8.738,7.332 12.317,21.49 1.194,39.057 26.32,-15.473 31.565,-41.994 7.978,-57.685 l -32.07,-34.297 c 5.918,-5.55 11.24,-11.6 15.947,-18.066 l 39.28,15.776 c -3.942,13.69 5.833,31.512 19.77,43.31 -8.055,-17.288 -4.826,-30.08 2.562,-37.103 1.63,17.39 10.64,29.193 18.733,40.064 2.73,-15.665 6.79,-31.493 -0.213,-45.987 11.016,1.56 21.2,11.568 20.338,31.877 14.362,-25.313 6.11,-49.702 -20.742,-51.52 l -71.135,-9.892 c 12.757,-22.982 18.676,-49.823 17.015,-77.475 14.188,-34.708 50.058,-11.816 54.523,49.16 27.425,-80.347 67.081,-38.617 58.825,24.513 11.808,-23.38 21.835,-35.013 29.862,-36.247 -10.772,-91.925 -40.458,-191.57 -77.637,-250.748 l 15.823,-9.942 c 50.328,80.106 85.112,220.65 84.88,331.547 C 521.655,285.828 476.905,45.13 324.97,17.54 Z m -29.458,476.913 -0.026,0.016 -0.015,0.05 c 0.015,-0.02 0.027,-0.044 0.042,-0.067 z m 26.543,-318.492 h 0.01 v -0.007 l -0.01,0.008 z m -53.348,-41.716 c 0.866,-0.027 1.757,0.073 2.652,0.313 4.774,1.28 7.467,5.945 6.187,10.72 -1.28,4.776 -5.943,7.47 -10.72,6.19 -4.775,-1.28 -7.468,-5.943 -6.188,-10.72 0.96,-3.584 3.823,-5.993 7.21,-6.435 0.282,-0.036 0.568,-0.06 0.857,-0.068 z M 204.904,297.13 c 11.878,-0.2 22.637,6.756 26.172,22.487 -0.008,35.88 -9.557,68.823 -42.137,77.412 -27.624,7.283 -69.725,-11.398 -84.12,-53.663 12.28,-21.078 37.362,-21.986 62.838,22.592 -12.583,-41.596 14.386,-68.444 37.246,-68.83 z"
|
||||
fill="#003fb2"
|
||||
fill-opacity="1"
|
||||
filter="url(#shadow-1)"
|
||||
transform="matrix(0.9,0,0,0.9,25.6,25.6)"
|
||||
id="path37"
|
||||
style="stroke:#000000;stroke-width:5.55555556;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.7 KiB |
160
icons/tmr/reserve.svg
Normal file
@ -0,0 +1,160 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
style="height: 512px; width: 512px;"
|
||||
version="1.1"
|
||||
id="svg41"
|
||||
sodipodi:docname="reserve.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata45">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1963"
|
||||
inkscape:window-height="1393"
|
||||
id="namedview43"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.4355469"
|
||||
inkscape:cx="257.8922"
|
||||
inkscape:cy="255.21477"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg41" />
|
||||
<defs
|
||||
id="defs35">
|
||||
<filter
|
||||
id="shadow-1"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(248, 231, 28, 1)"
|
||||
result="flood"
|
||||
id="feFlood2" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite4" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="40"
|
||||
result="blur"
|
||||
id="feGaussianBlur6" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="0"
|
||||
result="offset"
|
||||
id="feOffset8" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite10" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-6"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood13" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite15" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur17" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset19" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite21" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-7"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood24" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite26" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur28" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset30" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite32" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g
|
||||
class=""
|
||||
id="g39"
|
||||
style="stroke:#000000;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill:#7db27d;fill-opacity:1"
|
||||
transform="translate(0,0)">
|
||||
<path
|
||||
d="M149.688 85.625c-1.234.005-2.465.033-3.72.063-33.913.806-75.48 10.704-127.25 33.718V362.78c60.77-28.82 106.718-37.067 144.22-33.092 33.502 3.55 59.685 16.66 83.562 31.187v-242.97c-23.217-17.744-50.195-30.04-85.97-32-3.52-.192-7.142-.296-10.843-.28zm211.968 0c-3.7-.016-7.322.088-10.844.28-35.773 1.96-62.75 14.256-85.968 32v242.97c23.876-14.527 50.06-27.637 83.562-31.188 37.502-3.974 83.45 4.272 144.22 33.094V119.407c-51.77-23.014-93.337-32.912-127.25-33.72-1.255-.028-2.486-.056-3.72-.06zm5.72 261.78c-1.038-.002-2.074.017-3.095.033-4.808.075-9.43.37-13.905.843-33.932 3.597-59.603 17.976-85.53 34.44v.28c-6.554-1.99-13.02-2.37-19.408-.97-25.566-16.177-51.003-30.202-84.468-33.75-5.595-.592-11.44-.883-17.564-.842-32.04.213-71.833 9.778-124.687 35.937v42.53c60.77-28.823 106.714-37.067 144.218-33.092 18.545 1.965 34.837 6.845 49.75 13.28-4.682 6.064-9.308 13.268-13.875 21.688h117.156c-5.93-8.22-11.798-15.414-17.626-21.56 14.996-6.503 31.39-11.43 50.062-13.408 37.503-3.974 83.448 4.27 144.22 33.094v-42.53c-53.16-26.31-93.115-35.863-125.25-35.97z"
|
||||
fill="#087505"
|
||||
fill-opacity="1"
|
||||
transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)"
|
||||
filter="url(#shadow-1)"
|
||||
id="path37"
|
||||
style="stroke:#000000;stroke-width:11.11111111;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill:#7db27d;fill-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 45 KiB |
104
icons/tmr/sort-reserve-humide.svg
Normal file
@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
style="height: 256px; width: 256px;"
|
||||
version="1.1"
|
||||
id="svg24"
|
||||
sodipodi:docname="sort-reserve-humide.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata30">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs28" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2660"
|
||||
inkscape:window-height="1472"
|
||||
id="namedview26"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.4393497"
|
||||
inkscape:cx="557.39157"
|
||||
inkscape:cy="411.60399"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg24"
|
||||
inkscape:document-rotation="0" />
|
||||
<g
|
||||
id="g881"
|
||||
transform="translate(2.1482304,2.80716)"
|
||||
style="fill:#ffffff;stroke:#7d7db2;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal">
|
||||
<path
|
||||
d="m 243.94189,104.37921 -82.23331,178.13543 82.23331,27.44784 z"
|
||||
class=""
|
||||
fill="#f4e3d7"
|
||||
fill-opacity="1"
|
||||
id="path2"
|
||||
style="fill:#ffffff;stroke:#7d7db2;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" />
|
||||
<path
|
||||
d="m 263.7837,104.37921 v 205.58327 l 82.23331,-27.44784 z"
|
||||
class=""
|
||||
fill="#f4e3d7"
|
||||
fill-opacity="1"
|
||||
id="path4"
|
||||
style="fill:#ffffff;stroke:#7d7db2;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" />
|
||||
<path
|
||||
d="M 168.21228,221.005 18.274279,239.7445 141.75653,278.32581 Z"
|
||||
class=""
|
||||
fill="#f4e3d7"
|
||||
fill-opacity="1"
|
||||
id="path6"
|
||||
style="fill:#ffffff;stroke:#7d7db2;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" />
|
||||
<path
|
||||
d="M 339.51331,221.005 365.96906,278.32581 489.5395,239.7445 Z"
|
||||
class=""
|
||||
fill="#f4e3d7"
|
||||
fill-opacity="1"
|
||||
id="path8"
|
||||
style="fill:#ffffff;stroke:#7d7db2;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" />
|
||||
<path
|
||||
d="M -0.24475089,254.73609 114.97007,398.80973 230.27308,326.7178 Z"
|
||||
class=""
|
||||
fill="#f4e3d7"
|
||||
fill-opacity="1"
|
||||
id="path10"
|
||||
style="fill:#ffffff;stroke:#7d7db2;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" />
|
||||
<path
|
||||
d="M 507.94829,254.73609 277.45251,326.7178 392.75552,398.80973 Z"
|
||||
class=""
|
||||
fill="#f4e3d7"
|
||||
fill-opacity="1"
|
||||
id="path12"
|
||||
style="fill:#ffffff;stroke:#7d7db2;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" />
|
||||
<path
|
||||
d="M 253.8628,335.42615 147.37837,402.00647 H 360.34722 Z"
|
||||
class=""
|
||||
fill="#f4e3d7"
|
||||
fill-opacity="1"
|
||||
id="path14"
|
||||
style="fill:#ffffff;stroke:#7d7db2;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.1 KiB |
133
icons/tmr/sort-reserve.svg
Normal file
@ -0,0 +1,133 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
style="height: 512px; width: 512px;"
|
||||
version="1.1"
|
||||
id="svg32"
|
||||
sodipodi:docname="sort-reserve.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata36">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2318"
|
||||
inkscape:window-height="1268"
|
||||
id="namedview34"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.7031648"
|
||||
inkscape:cx="1044.9871"
|
||||
inkscape:cy="610.71305"
|
||||
inkscape:window-x="518"
|
||||
inkscape:window-y="680"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg32"
|
||||
inkscape:document-rotation="0" />
|
||||
<defs
|
||||
id="defs24">
|
||||
<filter
|
||||
id="shadow-6"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood2" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite4" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur6" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset8" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite10" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-7"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood13" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite15" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur17" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset19" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite21" />
|
||||
</filter>
|
||||
</defs>
|
||||
<path
|
||||
d="M 0,0 H 512 V 512 H 0 Z"
|
||||
fill="#4a4a4a"
|
||||
fill-opacity="0.5"
|
||||
id="path26"
|
||||
style="stroke-width:1;fill:#4a4a4a;fill-opacity:0.01" />
|
||||
<g
|
||||
class=""
|
||||
transform="translate(1,-1)"
|
||||
id="g30"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#7d7db2;stroke-width:13;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">
|
||||
<path
|
||||
d="m 373.563,18.406 c -15.616,-0.167 -27.91,4.622 -32.563,14.75 -22.778,49.605 -48.743,87.14 -79.094,117.28 3.047,1.015 6.046,2.29 8.938,3.783 12.987,6.708 25.268,17.78 35.312,30.843 10.044,13.062 17.85,28.114 20.78,43.5 0.746,3.908 1.16,7.885 1.158,11.843 38.97,-24.36 85.058,-41.223 140.875,-51.312 14.91,-2.697 23.652,-28.632 21.405,-58.656 l -35.156,-1 30.56,-24.813 C 481.63,90.117 474.765,75.87 464.623,63.904 449.095,45.59 428.193,32.528 407.903,25.218 l -25.963,15.594 2.812,-21.5 c -3.875,-0.55 -7.61,-0.87 -11.188,-0.907 z M 246.938,166.562 c -1.063,0.052 -2.06,0.226 -3,0.47 -11.976,10.254 -24.61,19.597 -37.938,28.28 0.842,0.33 1.67,0.667 2.5,1.032 14.123,6.192 27.438,17.145 38.47,30.625 13.356,16.322 23.62,36.94 25.624,57.75 10.334,-10.367 21.24,-19.943 32.844,-28.72 4.096,-6.555 4.93,-14.468 3.125,-23.938 -2.184,-11.46 -8.642,-24.43 -17.25,-35.625 -8.61,-11.194 -19.38,-20.622 -29.063,-25.625 -6.052,-3.126 -11.154,-4.45 -15.313,-4.25 z m -61.907,43.282 c -1.385,0.053 -2.69,0.27 -3.968,0.562 -37,20.762 -79.088,37.985 -127.312,56 0.574,0.042 1.14,0.093 1.72,0.156 10.627,1.156 21.076,5.008 31.155,10.875 L 124.313,261 108.5,293.72 c 5.995,5.432 11.803,11.477 17.344,18 20.76,24.434 37.964,55.865 47.094,88.092 0.002,0.01 -0.003,0.022 0,0.032 2.98,10.508 5.11,20.916 6.312,31 20.99,-48.438 44.38,-89.26 72.344,-123 7.3,-21.48 -2.186,-48.408 -19.063,-69.03 -9.44,-11.538 -20.976,-20.718 -31.53,-25.345 -5.936,-2.604 -11.27,-3.808 -15.97,-3.626 z m 141.626,54.844 c -7.31,5.05 -14.462,10.51 -21.437,16.312 39.16,9.26 60.953,35.722 80.655,62.156 10.464,14.04 20.598,28.11 33.125,40.688 24.19,9.147 43.17,6.38 63.906,-14.938 -92.165,-27.78 -96.11,-92.61 -156.25,-104.22 z M 48.594,284.906 c -10.873,0.225 -18.26,5.755 -23.344,16.594 -5.81,12.387 -7.114,32.47 0.438,57.063 5.75,18.73 16.52,37.718 28.75,51.625 12.23,13.906 25.9,22.076 35.374,22.406 h 0.032 c 3.717,0.13 6.553,-0.682 8.812,-2.75 l -0.187,-0.188 2.093,-2.094 c 0.793,-1.168 1.52,-2.548 2.187,-4.187 2.81,-6.9 3.28,-18.552 -1.844,-33 -6.885,-19.417 -19.12,-31.932 -33.375,-34.78 l -22.968,-4.564 19.813,-12.5 38.47,-24.186 c -16.65,-16.822 -34.55,-27.607 -49.376,-29.22 -1.7,-0.184 -3.323,-0.25 -4.876,-0.218 z m 236.25,5.406 -24.53,25.375 c 100.442,17.878 55.45,141.005 159.31,176.188 l -24.78,-57.28 c 32.766,16.15 67.39,22.623 97.72,12.03 -135.77,-41.948 -96.32,-126.983 -207.72,-156.313 z m -169.47,38.22 -25.968,16.343 c 13.18,8.5 23.21,22.565 29.125,39.25 2.57,7.244 4.133,14.205 4.75,20.78 l 23.44,-23.374 c -8.08,-19.19 -19.035,-37.566 -31.345,-53 z m 38.376,72.374 -42.063,42 -0.156,-0.156 c -4.255,3.942 -9.456,6.765 -15.186,7.938 23.268,14.873 44.644,19.346 56.812,9.562 4.26,-3.426 7.043,-8.36 8.47,-14.406 -0.41,-12.684 -2.602,-26.615 -6.657,-40.906 -0.382,-1.346 -0.806,-2.686 -1.22,-4.032 z"
|
||||
fill="#ffffff"
|
||||
fill-opacity="1"
|
||||
id="path28"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#7d7db2;stroke-width:13;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 17 KiB |
127
icons/tmr/trounoir.svg
Normal file
@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
style="height: 512px; width: 512px;"
|
||||
version="1.1"
|
||||
id="svg32"
|
||||
sodipodi:docname="trounoir.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata36">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1879"
|
||||
inkscape:window-height="1569"
|
||||
id="namedview34"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.4374483"
|
||||
inkscape:cx="256"
|
||||
inkscape:cy="256"
|
||||
inkscape:window-x="460"
|
||||
inkscape:window-y="170"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg32"
|
||||
inkscape:document-rotation="0" />
|
||||
<defs
|
||||
id="defs24">
|
||||
<filter
|
||||
id="shadow-6"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood2" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite4" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur6" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset8" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite10" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-7"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood13" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite15" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur17" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset19" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite21" />
|
||||
</filter>
|
||||
</defs>
|
||||
<path
|
||||
d="M0 0h512v512H0z"
|
||||
fill="#4a4a4a"
|
||||
fill-opacity="0.5"
|
||||
id="path26"
|
||||
style="fill:#3a174d;fill-opacity:0.69999999" />
|
||||
<path
|
||||
d="m 329.547,18.115 c -30.61,99.22 -47.583,151.205 -86.88,156.778 -18.626,2.642 -42.988,-19.225 -70.16,-50.29 15.47,30.702 21.275,55.265 10.845,61.348 -15.787,9.21 -51.095,-6.94 -106.815,-30.837 31.653,20.827 83.667,50.18 77.358,58.63 -8.074,10.81 -77.23,-4.706 -130.866,-13.163 89.224,25.398 137.61,55.572 137.61,82.387 0,18.423 -48.845,62.18 -71.888,83.928 19.558,-11.397 64.736,-24.44 76.777,-2.99 13.335,23.758 -6.577,61.6 -28.5,128.027 31.39,-46.19 73.363,-108.122 90.734,-106.49 12.248,1.15 -4.805,60.692 -10.47,98.71 21.547,-80.082 46.534,-132.5 90.153,-131.015 29.665,1.01 58.022,30.762 88.99,52.047 -16.188,-19.81 -45.975,-47.99 -39.55,-53.243 8.9,-7.276 56.48,12.547 94.224,25.726 -24.982,-17.962 -68.644,-43.88 -61.653,-50.852 10.417,-10.387 72.436,1.332 117.49,7.178 C 419.2,303.266 370.1,289.807 359.616,255.461 c -5.283,-17.31 10.853,-40.3 40.89,-68.038 -31.377,17.197 -54.588,28.694 -63.737,12.392 -11.576,-20.622 11.374,-65.883 35.238,-126.06 -21.135,32.47 -48.532,83.487 -55.254,77.174 -8.972,-8.425 5.598,-77.597 12.795,-132.813 h -0.003 z M 21.45,18.27 V 41.63 C 69.97,69.067 116.703,104.02 162.783,144.416 129.015,102.731 95.443,60.626 68.758,18.27 Z m 175.79,0 c 18.465,37.356 34.503,76.96 48.475,117.97 -5.007,-39.79 -9.898,-79.367 -12.264,-117.97 h -36.21 z m 160.022,0 c -7.18,26.672 -15.416,53.437 -25.116,80.593 15.405,-27.34 30.698,-54.514 46.723,-80.593 H 357.26 Z m 105.123,0 c -27.895,50.718 -63.73,99.873 -105.707,147.755 46.514,-37.68 92.9,-75.343 140.164,-103.37 V 18.27 Z m 34.455,160.02 c -36.077,17.98 -74.843,34.036 -115.635,47.89 38.908,-6.17 77.882,-12.105 115.635,-15.77 z m -206.266,42.868 c 9.35,0 16.93,7.58 16.93,16.932 0,9.35 -7.58,16.93 -16.93,16.93 -9.35,0 -16.93,-7.58 -16.93,-16.93 0,-9.35 7.58,-16.932 16.93,-16.932 z m -52.06,1.598 c 15.508,0 28.082,12.57 28.082,28.08 0,9.718 -4.938,18.28 -12.44,23.322 3.614,3.843 5.842,9.002 5.842,14.694 0,11.86 -9.613,21.474 -21.473,21.474 -11.86,0 -21.474,-9.615 -21.474,-21.474 0,-5.687 2.228,-10.842 5.837,-14.684 -7.51,-5.04 -12.453,-13.608 -12.453,-23.332 0,-15.51 12.57,-28.08 28.08,-28.08 z M 21.45,234.078 v 38.547 c 31.87,-4.584 64.46,-5.693 97.532,-4.09 -33.727,-10.19 -67.407,-20.35 -97.53,-34.457 z m 265.82,28.377 c 9.35,0 16.93,7.58 16.93,16.932 0,9.35 -7.58,16.93 -16.93,16.93 -9.35,0 -16.932,-7.58 -16.932,-16.93 0,-9.35 7.58,-16.932 16.932,-16.932 z M 129.494,294.05 c -36.153,11.99 -72.24,20.293 -108.043,24.313 v 51.393 c 30.994,-28.64 69.426,-52.264 108.044,-75.703 v -0.002 z m 5.84,88.645 c -37.923,30.72 -75.607,61.482 -113.885,87.02 v 23.943 h 29.784 c 24.02,-37.76 52.365,-74.765 84.1,-110.963 z m 202.07,11.096 c 26.807,33.093 53.226,66.414 76.508,99.87 h 59.568 c -46.586,-27.078 -91.877,-61.12 -136.074,-99.87 z m -52.562,9.93 c -3.175,30.26 -6.39,60.5 -10.512,89.94 h 20.44 c -4.51,-29.083 -7.904,-59.17 -9.926,-89.94 z m 26.865,13.432 c 11.346,25.473 22.374,51.18 32.705,76.508 h 23.36 c -19.395,-23.9 -38.105,-49.64 -56.065,-76.508 z"
|
||||
fill="#602000"
|
||||
fill-opacity="1"
|
||||
id="path28"
|
||||
style="fill:#380f4d;fill-opacity:1" />
|
||||
</svg>
|
After Width: | Height: | Size: 6.1 KiB |
159
icons/tmr/urgence.svg
Normal file
@ -0,0 +1,159 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
style="height: 512px; width: 512px;"
|
||||
version="1.1"
|
||||
id="svg41"
|
||||
sodipodi:docname="urgence.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata45">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2038"
|
||||
inkscape:window-height="1243"
|
||||
id="namedview43"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.4355469"
|
||||
inkscape:cx="256"
|
||||
inkscape:cy="256"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg41" />
|
||||
<defs
|
||||
id="defs35">
|
||||
<filter
|
||||
id="shadow-1"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(248, 231, 28, 1)"
|
||||
result="flood"
|
||||
id="feFlood2" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite4" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="40"
|
||||
result="blur"
|
||||
id="feGaussianBlur6" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="0"
|
||||
result="offset"
|
||||
id="feOffset8" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite10" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-6"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood13" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite15" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur17" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset19" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite21" />
|
||||
</filter>
|
||||
<filter
|
||||
id="shadow-7"
|
||||
height="300%"
|
||||
width="300%"
|
||||
x="-100%"
|
||||
y="-100%">
|
||||
<feFlood
|
||||
flood-color="rgba(72, 186, 255, 1)"
|
||||
result="flood"
|
||||
id="feFlood24" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="atop"
|
||||
result="composite"
|
||||
id="feComposite26" />
|
||||
<feGaussianBlur
|
||||
in="composite"
|
||||
stdDeviation="8"
|
||||
result="blur"
|
||||
id="feGaussianBlur28" />
|
||||
<feOffset
|
||||
dx="5"
|
||||
dy="15"
|
||||
result="offset"
|
||||
id="feOffset30" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
id="feComposite32" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g
|
||||
class=""
|
||||
id="g39"
|
||||
style="stroke:#000000;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none">
|
||||
<path
|
||||
d="m 103.432,17.844 c -1.118,0.005 -2.234,0.032 -3.348,0.08 -2.547,0.11 -5.083,0.334 -7.604,0.678 -20.167,2.747 -39.158,13.667 -52.324,33.67 -24.613,37.4 2.194,98.025 56.625,98.025 0.536,0 1.058,-0.012 1.583,-0.022 v 0.704 h 60.565 c -10.758,31.994 -30.298,66.596 -52.448,101.43 -2.162,3.4 -4.254,6.878 -6.29,10.406 l 34.878,35.733 -56.263,9.423 c -32.728,85.966 -27.42,182.074 48.277,182.074 v -0.002 l 9.31,0.066 c 23.83,-0.57 46.732,-4.298 61.325,-12.887 4.174,-2.458 7.63,-5.237 10.467,-8.42 h -32.446 c -20.33,5.95 -40.8,-6.94 -47.396,-25.922 -8.956,-25.77 7.52,-52.36 31.867,-60.452 5.803,-1.93 11.723,-2.834 17.565,-2.834 v -0.406 h 178.33 c -0.57,-44.403 16.35,-90.125 49.184,-126 23.955,-26.176 42.03,-60.624 51.3,-94.846 l -41.225,-24.932 38.272,-6.906 -43.37,-25.807 h -0.005 l 0.002,-0.002 0.002,0.002 52.127,-8.85 C 457.16,52.713 433.552,23.734 385.022,23.734 341.14,32.26 222.11,35.29 149.34,28.496 134.452,21.733 118.793,17.773 103.432,17.844 Z m 0.464,18.703 c 13.137,0.043 27.407,3.804 41.247,10.63 l 0.033,-0.07 c 4.667,4.735 8.542,9.737 11.68,14.985 H 82.92 l 10.574,14.78 c 10.608,14.83 19.803,31.99 21.09,42.024 0.643,5.017 -0.11,7.167 -1.814,8.836 -1.705,1.67 -6.228,3.875 -15.99,3.875 -40.587,0 -56.878,-44.952 -41.012,-69.06 C 66.238,46.64 79.582,39.22 95.002,37.12 c 2.89,-0.395 5.863,-0.583 8.894,-0.573 z M 118.5,80.78 h 46.28 c 4.275,15.734 3.656,33.07 -0.544,51.51 H 131.52 c 1.9,-5.027 2.268,-10.574 1.6,-15.77 -1.527,-11.913 -7.405,-24.065 -14.62,-35.74 z m 101.553,317.095 c 6.44,6.84 11.192,15.31 13.37,24.914 3.797,16.736 3.092,31.208 -1.767,43.204 -4.526,11.175 -12.576,19.79 -22.29,26 h 237.19 c 14.448,0 24.887,-5.678 32.2,-14.318 7.312,-8.64 11.2,-20.514 10.705,-32.352 -0.186,-4.473 -0.978,-8.913 -2.407,-13.18 l -69.91,-8.205 42.017,-20.528 c -8.32,-3.442 -18.64,-5.537 -31.375,-5.537 H 220.053 Z m -42.668,0.506 c -1.152,-0.003 -2.306,0.048 -3.457,0.153 -2.633,0.242 -5.256,0.775 -7.824,1.63 -15.11,5.02 -25.338,21.54 -20.11,36.583 3.673,10.57 15.347,17.71 25.654,13.938 l 1.555,-0.57 h 43.354 c 0.946,-6.36 0.754,-13.882 -1.358,-23.192 -3.71,-16.358 -20.543,-28.483 -37.815,-28.54 z"
|
||||
fill="#b41e00"
|
||||
fill-opacity="1"
|
||||
transform="matrix(0.9,0,0,0.9,25.6,25.6)"
|
||||
filter="url(#shadow-1)"
|
||||
id="path37"
|
||||
style="stroke:#000000;stroke-width:11.11111111;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 13 KiB |
BIN
icons/voyageurs/personnage.webp
Normal file
After Width: | Height: | Size: 9.1 KiB |
104
lang/fr.json
@ -1,54 +1,58 @@
|
||||
{
|
||||
"ACTOR": {
|
||||
"TypePersonnage": "Personnage",
|
||||
"TypeCreature": "Créature",
|
||||
"TypeEntite": "Entité de cauchemar",
|
||||
"TypeCommerce": "Commerce",
|
||||
"TypeVehicule": "Véhicule"
|
||||
},
|
||||
"ITEM": {
|
||||
"TypeArme": "Arme",
|
||||
"TypeArmure": "Armure",
|
||||
"TypeBlessure": "Blessure",
|
||||
"TypeCasetmr": "TMR spéciale",
|
||||
"TypeChant": "Chant",
|
||||
"TypeCompetence": "Compétence",
|
||||
"TypeCompetencecreature": "Compétence de créature",
|
||||
"TypeConteneur": "Conteneur",
|
||||
"TypeDanse": "Danse",
|
||||
"TypeExtraitpoetique": "Extrait poetique",
|
||||
"TypeFaune": "Faune",
|
||||
"TypeGemme": "Gemme",
|
||||
"TypeHerbe": "Herbe",
|
||||
"TypeIngredient": "Ingrédient",
|
||||
"TypeJeu": "Jeu",
|
||||
"TypeLivre": "Livre",
|
||||
"TypeMaladie": "Maladie",
|
||||
"TypeMeditation": "Méditation",
|
||||
"TypeMonnaie": "Monnaie",
|
||||
"TypeMunition": "Munition",
|
||||
"TypeMusique": "Musique",
|
||||
"TypeNombreastral": "Nombre astral",
|
||||
"TypeNourritureboisson": "Nourriture & boisson",
|
||||
"TypeObjet": "Objet",
|
||||
"TypeOeuvre": "Oeuvre",
|
||||
"TypeOmbre": "Ombre de Thanatos",
|
||||
"TypePlante": "Plante",
|
||||
"TypePoison": "Poison",
|
||||
"TypePossession": "Possession",
|
||||
"TypePotion": "Potion",
|
||||
"TypeQueue": "Queue de Dragon",
|
||||
"TypeRecettealchimique": "Recette alchimique",
|
||||
"TypeRecettecuisine": "Recette de cuisine",
|
||||
"TypeRencontre": "Rencontre TMR",
|
||||
"TypeService": "Service",
|
||||
"TypeSignedraconique": "Signe draconique",
|
||||
"TypeSort": "Sort",
|
||||
"TypeSortreserve": "Sort en réserve",
|
||||
"TypeSouffle": "Souffle de Dragon",
|
||||
"TypeTache": "Tâche",
|
||||
"TypeTarot": "Carte de tarot",
|
||||
"TypeTete": "Tête de Dragon"
|
||||
"TYPES": {
|
||||
"Actor": {
|
||||
"personnage": "Personnage",
|
||||
"creature": "Créature",
|
||||
"entite": "Entité de cauchemar",
|
||||
"commerce": "Commerce",
|
||||
"vehicule": "Véhicule"
|
||||
},
|
||||
"Item": {
|
||||
"arme": "Arme",
|
||||
"armure": "Armure",
|
||||
"blessure": "Blessure",
|
||||
"casetmr": "Case TMR spéciale",
|
||||
"chant": "Chant",
|
||||
"competence": "Compétence",
|
||||
"competencecreature": "Compétence de créature",
|
||||
"conteneur": "Conteneur",
|
||||
"danse": "Danse",
|
||||
"empoignade": "Empoignade",
|
||||
"extraitpoetique": "Extrait poetique",
|
||||
"faune": "Faune",
|
||||
"gemme": "Gemme",
|
||||
"herbe": "Herbe",
|
||||
"ingredient": "Ingrédient",
|
||||
"jeu": "Jeu",
|
||||
"livre": "Livre",
|
||||
"maladie": "Maladie",
|
||||
"meditation": "Méditation",
|
||||
"monnaie": "Monnaie",
|
||||
"munition": "Munition",
|
||||
"musique": "Musique",
|
||||
"nombreastral": "Nombre astral",
|
||||
"nourritureboisson": "Nourriture & boisson",
|
||||
"objet": "Objet",
|
||||
"oeuvre": "Oeuvre",
|
||||
"ombre": "Ombre de Thanatos",
|
||||
"plante": "Plante",
|
||||
"poison": "Poison",
|
||||
"possession": "Possession",
|
||||
"potion": "Potion",
|
||||
"queue": "Queue de Dragon",
|
||||
"race": "Race",
|
||||
"recettealchimique": "Recette alchimique",
|
||||
"recettecuisine": "Recette de cuisine",
|
||||
"rencontre": "Rencontre TMR",
|
||||
"service": "Service",
|
||||
"signedraconique": "Signe draconique",
|
||||
"sort": "Sort",
|
||||
"sortreserve": "Sort en réserve",
|
||||
"souffle": "Souffle de Dragon",
|
||||
"tache": "Tâche",
|
||||
"tarot": "Carte de tarot",
|
||||
"tete": "Tête de Dragon"
|
||||
}
|
||||
},
|
||||
"EFFECT": {
|
||||
"StatusStunned": "Sonné",
|
||||
|
65
module/achat-vente/chat-vente.js
Normal file
@ -0,0 +1,65 @@
|
||||
import { SYSTEM_RDD } from "../constants.js";
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
|
||||
const DETAIL_VENTE = 'detailVente';
|
||||
const NB_LOTS = 'nbLotss';
|
||||
|
||||
export class ChatVente {
|
||||
|
||||
static getDetailVente(chatMessageId) {
|
||||
const chatMessage = game.messages.get(chatMessageId)
|
||||
if (!chatMessage) {
|
||||
return undefined;
|
||||
}
|
||||
const nbLots = chatMessage.getFlag(SYSTEM_RDD, NB_LOTS)
|
||||
const detail = foundry.utils.duplicate(chatMessage.getFlag(SYSTEM_RDD, DETAIL_VENTE))
|
||||
if (!detail.item) {
|
||||
ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes")
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const vendeur = detail.vendeurId ? game.actors.get(detail.vendeurId) : undefined;
|
||||
return foundry.utils.mergeObject(detail,
|
||||
{
|
||||
alias: vendeur?.name ?? game.user.name,
|
||||
vendeur,
|
||||
nbLots: nbLots,
|
||||
chatMessageIdVente: chatMessageId
|
||||
})
|
||||
}
|
||||
|
||||
static getDetailAchatVente(chatMessageId) {
|
||||
const acheteur = RdDUtility.getSelectedActor()
|
||||
const detail = ChatVente.getDetailVente(chatMessageId)
|
||||
if (!acheteur && !detail.vendeur) {
|
||||
ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement");
|
||||
return undefined;
|
||||
}
|
||||
return foundry.utils.mergeObject(detail, { acheteur })
|
||||
}
|
||||
|
||||
static async diminuerQuantiteAchatVente(chatMessageId, quantite) {
|
||||
const chatMessage = game.messages.get(chatMessageId)
|
||||
const vente = ChatVente.getDetailVente(chatMessageId)
|
||||
vente.nbLots = Math.max(0, vente.nbLots - quantite)
|
||||
await chatMessage.setFlag(SYSTEM_RDD, NB_LOTS, vente.nbLots)
|
||||
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente);
|
||||
chatMessage.update({ content: html });
|
||||
chatMessage.render(true);
|
||||
}
|
||||
|
||||
static async displayAchatVente(vente) {
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente);
|
||||
const chatMessage = await ChatMessage.create(RdDUtility.chatDataSetup(html))
|
||||
await chatMessage.setFlag(SYSTEM_RDD, NB_LOTS, vente.nbLots)
|
||||
await chatMessage.setFlag(SYSTEM_RDD, DETAIL_VENTE, {
|
||||
item: vente.item,
|
||||
properties: vente.item.getProprietes(),
|
||||
vendeurId: vente.vendeurId,
|
||||
tailleLot: vente.tailleLot,
|
||||
quantiteIllimite: vente.quantiteIllimite,
|
||||
prixLot: vente.prixLot
|
||||
})
|
||||
}
|
||||
}
|
@ -1,35 +1,13 @@
|
||||
import { Misc } from "./misc.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
import { ChatVente } from "./chat-vente.js";
|
||||
|
||||
export class DialogItemAchat extends Dialog {
|
||||
|
||||
static preparerAchat(chatButton) {
|
||||
const vendeurId = chatButton.attributes['data-vendeurId']?.value;
|
||||
const vendeur = vendeurId ? game.actors.get(vendeurId) : undefined;
|
||||
const acheteur = RdDUtility.getSelectedActor();
|
||||
const json = chatButton.attributes['data-jsondata']?.value;
|
||||
if (!acheteur && !vendeur) {
|
||||
ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement");
|
||||
return undefined;
|
||||
}
|
||||
if (!json) {
|
||||
ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes")
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
item: JSON.parse(json),
|
||||
vendeur,
|
||||
acheteur,
|
||||
nbLots: parseInt(chatButton.attributes['data-quantiteNbLots']?.value),
|
||||
tailleLot: parseInt(chatButton.attributes['data-tailleLot']?.value ?? 1),
|
||||
prixLot: Number(chatButton.attributes['data-prixLot']?.value ?? 0),
|
||||
quantiteIllimite: chatButton.attributes['data-quantiteIllimite']?.value == 'true',
|
||||
chatMessageIdVente: RdDUtility.findChatMessageId(chatButton),
|
||||
};
|
||||
return ChatVente.getDetailAchatVente(RdDUtility.findChatMessageId(chatButton))
|
||||
}
|
||||
|
||||
|
||||
static async onAcheter({ item, vendeur, acheteur, tailleLot, prixLot, nbLots, quantiteIllimite, chatMessageIdVente }) {
|
||||
const venteData = {
|
||||
item,
|
||||
@ -38,17 +16,21 @@ export class DialogItemAchat extends Dialog {
|
||||
acheteur,
|
||||
tailleLot,
|
||||
quantiteIllimite,
|
||||
quantiteNbLots: nbLots,
|
||||
nbLots,
|
||||
choix: { seForcer: false, supprimerSiZero: true },
|
||||
prixLot,
|
||||
isVente: prixLot > 0,
|
||||
isConsommable: item.type == 'nourritureboisson' && acheteur?.isPersonnage(),
|
||||
chatMessageIdVente
|
||||
};
|
||||
}
|
||||
if (venteData.vendeur?.id == venteData.acheteur?.id) {
|
||||
ui.notifications.info("Inutile de se vendre à soi-même")
|
||||
return
|
||||
}
|
||||
|
||||
DialogItemAchat.changeNombreLots(venteData, 1);
|
||||
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData);
|
||||
new DialogItemAchat(html, venteData).render(true);
|
||||
DialogItemAchat.changeNombreLots(venteData, 1)
|
||||
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData)
|
||||
new DialogItemAchat(html, venteData).render(true)
|
||||
}
|
||||
|
||||
static changeNombreLots(venteData, nombreLots) {
|
||||
@ -116,18 +98,18 @@ export class DialogItemAchat extends Dialog {
|
||||
this.venteData.choix.seForcer = event.currentTarget.checked;
|
||||
}
|
||||
|
||||
setNombreLots(nombreLots) {
|
||||
setNombreLots(nbLots) {
|
||||
|
||||
if (!this.venteData.quantiteIllimite) {
|
||||
if (!this.venteData.quantiteIllimite && nombreLots > this.venteData.quantiteNbLots) {
|
||||
ui.notifications.warn(`Seulement ${this.venteData.quantiteNbLots} lots disponibles, vous ne pouvez pas en prendre ${nombreLots}`)
|
||||
if (!this.venteData.quantiteIllimite && nbLots > this.venteData.nbLots) {
|
||||
ui.notifications.warn(`Seulement ${this.venteData.nbLots} lots disponibles, vous ne pouvez pas en prendre ${nbLots}`)
|
||||
}
|
||||
nombreLots = Math.min(nombreLots, this.venteData.quantiteNbLots);
|
||||
nbLots = Math.min(nbLots, this.venteData.nbLots);
|
||||
}
|
||||
|
||||
DialogItemAchat.changeNombreLots(this.venteData, nombreLots);
|
||||
DialogItemAchat.changeNombreLots(this.venteData, nbLots);
|
||||
|
||||
this.html.find(".nombreLots").val(nombreLots);
|
||||
this.html.find(".nombreLots").val(nbLots);
|
||||
this.html.find(".prixTotal").text(this.venteData.prixTotal);
|
||||
this.html.find("span.total-sust").text(this.venteData.totalSust);
|
||||
this.html.find("span.total-desaltere").text(this.venteData.totalDesaltere);
|
@ -1,10 +1,11 @@
|
||||
import { HtmlUtility } from "./html-utility.js";
|
||||
import { HtmlUtility } from "../html-utility.js";
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
import { ChatVente } from "./chat-vente.js";
|
||||
|
||||
export class DialogItemVente extends Dialog {
|
||||
|
||||
static async display({ item, callback, quantiteMax = undefined }) {
|
||||
static async display({ item, quantiteMax = undefined }) {
|
||||
const quantite = quantiteMax ?? item.getQuantite() ?? 1;
|
||||
const isOwned = item.parent;
|
||||
const venteData = {
|
||||
item: item,
|
||||
alias: item.actor?.name ?? game.user.name,
|
||||
@ -13,17 +14,17 @@ export class DialogItemVente extends Dialog {
|
||||
prixUnitaire: item.calculerPrixCommercant(),
|
||||
prixLot: item.calculerPrixCommercant(),
|
||||
tailleLot: 1,
|
||||
quantiteNbLots: quantite,
|
||||
quantiteMaxLots: quantite,
|
||||
nbLots: quantite,
|
||||
maxLots: quantite,
|
||||
quantiteMax: quantite,
|
||||
quantiteIllimite: item.isItemCommerce() ? quantiteMax == undefined : !isOwned,
|
||||
isOwned: isOwned,
|
||||
};
|
||||
quantiteIllimite: item.isItemCommerce() ? quantiteMax == undefined : !item.parent,
|
||||
isOwned: item.parent,
|
||||
}
|
||||
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.html`, venteData);
|
||||
return new DialogItemVente(venteData, html, callback).render(true);
|
||||
return new DialogItemVente(venteData, html).render(true);
|
||||
}
|
||||
|
||||
constructor(venteData, html, callback) {
|
||||
constructor(venteData, html) {
|
||||
let options = { classes: ["dialogvente"], width: 400, height: 'fit-content', 'z-index': 99999 };
|
||||
|
||||
let conf = {
|
||||
@ -34,7 +35,6 @@ export class DialogItemVente extends Dialog {
|
||||
};
|
||||
|
||||
super(conf, options);
|
||||
this.callback = callback;
|
||||
this.venteData = venteData;
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ export class DialogItemVente extends Dialog {
|
||||
|
||||
this.html = html;
|
||||
this.html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value)));
|
||||
this.html.find(".quantiteNbLots").change(event => this.setNbLots(Number(event.currentTarget.value)));
|
||||
this.html.find(".nbLots").change(event => this.setNbLots(Number(event.currentTarget.value)));
|
||||
this.html.find(".quantiteIllimite").change(event => this.setQuantiteIllimite(event.currentTarget.checked));
|
||||
this.html.find(".prixLot").change(event => this.setPrixLot(Number(event.currentTarget.value)));
|
||||
|
||||
@ -52,16 +52,24 @@ export class DialogItemVente extends Dialog {
|
||||
|
||||
async onProposer(it) {
|
||||
this.updateVente(this.getChoixVente());
|
||||
this.callback(this.venteData);
|
||||
|
||||
this.venteData["properties"] = this.venteData.item.getProprietes();
|
||||
if (this.venteData.isOwned) {
|
||||
if (this.venteData.nbLots * this.venteData.tailleLot > this.venteData.quantiteMax) {
|
||||
ui.notifications.warn(`Vous avez ${this.venteData.quantiteMax} ${this.venteData.item.name}, ce n'est pas suffisant pour vendre ${this.venteData.nbLots} de ${this.venteData.tailleLot}`)
|
||||
return;
|
||||
}
|
||||
}
|
||||
await ChatVente.displayAchatVente(this.venteData)
|
||||
}
|
||||
|
||||
updateVente(update) {
|
||||
mergeObject(this.venteData, update);
|
||||
foundry.utils.mergeObject(this.venteData, update);
|
||||
}
|
||||
|
||||
getChoixVente() {
|
||||
return {
|
||||
quantiteNbLots: Number(this.html.find(".quantiteNbLots").val()),
|
||||
nbLots: Number(this.html.find(".nbLots").val()),
|
||||
tailleLot: Number(this.html.find(".tailleLot").val()),
|
||||
quantiteIllimite: this.html.find(".quantiteIllimite").is(':checked'),
|
||||
prixLot: Number(this.html.find(".prixLot").val())
|
||||
@ -77,26 +85,26 @@ export class DialogItemVente extends Dialog {
|
||||
const maxLots = Math.floor(this.venteData.quantiteMax / tailleLot);
|
||||
this.updateVente({
|
||||
tailleLot,
|
||||
quantiteNbLots: Math.min(maxLots, this.venteData.quantiteNbLots),
|
||||
quantiteMaxLots: maxLots,
|
||||
nbLots: Math.min(maxLots, this.venteData.nbLots),
|
||||
maxLots: maxLots,
|
||||
prixLot: (tailleLot * this.venteData.prixOrigine).toFixed(2)
|
||||
});
|
||||
|
||||
this.html.find(".prixLot").val(this.venteData.prixLot);
|
||||
this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots);
|
||||
this.html.find(".quantiteNbLots").attr("max", this.venteData.quantiteMaxLots)
|
||||
this.html.find(".nbLots").val(this.venteData.nbLots);
|
||||
this.html.find(".nbLots").attr("max", this.venteData.maxLots)
|
||||
}
|
||||
|
||||
setNbLots(nbLots) {
|
||||
this.updateVente({
|
||||
quantiteNbLots: this.venteData.isOwned ? Math.max(0, Math.min(nbLots, this.venteData.quantiteMaxLots)) : nbLots
|
||||
nbLots: this.venteData.isOwned ? Math.max(0, Math.min(nbLots, this.venteData.maxLots)) : nbLots
|
||||
})
|
||||
this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots);
|
||||
this.html.find(".nbLots").val(this.venteData.nbLots);
|
||||
}
|
||||
|
||||
setQuantiteIllimite(checked) {
|
||||
this.updateVente({ quantiteIllimite: checked })
|
||||
this.html.find(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles");
|
||||
HtmlUtility.showControlWhen(this.html.find(".quantiteNbLots"), !this.venteData.quantiteIllimite)
|
||||
HtmlUtility.showControlWhen(this.html.find(".nbLots"), !this.venteData.quantiteIllimite)
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
import { RdDActorSheet } from "./actor-sheet.js";
|
||||
|
||||
export class RdDActorEntiteSheet extends RdDActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["rdd", "sheet", "actor"],
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html",
|
||||
width: 640,
|
||||
height: 720,
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
// On competence change
|
||||
this.html.find('.creature-carac').change(async event => {
|
||||
let compName = event.currentTarget.attributes.compname.value;
|
||||
this.actor.updateCreatureCompetence(compName, "carac_value", parseInt(event.target.value));
|
||||
});
|
||||
this.html.find('.creature-niveau').change(async event => {
|
||||
let compName = event.currentTarget.attributes.compname.value;
|
||||
this.actor.updateCreatureCompetence(compName, "niveau", parseInt(event.target.value));
|
||||
});
|
||||
this.html.find('.creature-dommages').change(async event => {
|
||||
let compName = event.currentTarget.attributes.compname.value;
|
||||
this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -7,55 +7,54 @@ import { Misc } from "./misc.js";
|
||||
import { RdDCombatManager } from "./rdd-combat.js";
|
||||
import { RdDCarac } from "./rdd-carac.js";
|
||||
import { DialogSplitItem } from "./dialog-split-item.js";
|
||||
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
|
||||
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
||||
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
|
||||
import { STATUSES } from "./settings/status-effects.js";
|
||||
import { MAINS_DIRECTRICES } from "./actor.js";
|
||||
import { RdDBaseActorSheet } from "./actor/base-actor-sheet.js";
|
||||
import { RdDBaseActorReveSheet } from "./actor/base-actor-reve-sheet.js";
|
||||
import { ITEM_TYPES } from "./constants.js";
|
||||
import { RdDItem } from "./item.js";
|
||||
import { RdDItemBlessure } from "./item/blessure.js";
|
||||
import { RdDEmpoignade } from "./rdd-empoignade.js";
|
||||
import { RdDBaseActorSangSheet } from "./actor/base-actor-sang-sheet.js";
|
||||
import { RdDCoeur } from "./coeur/rdd-coeur.js";
|
||||
import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js";
|
||||
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
* @extends {ActorSheet}
|
||||
*/
|
||||
export class RdDActorSheet extends RdDBaseActorSheet {
|
||||
export class RdDActorSheet extends RdDBaseActorSangSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
RdDUtility.initAfficheContenu();
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["rdd", "sheet", "actor"],
|
||||
return foundry.utils.mergeObject(RdDBaseActorReveSheet.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html",
|
||||
width: 550,
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }],
|
||||
showCompNiveauBase: false,
|
||||
vueDetaillee: false
|
||||
});
|
||||
vueArchetype: false,
|
||||
}, { inplace: false });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
let formData = await super.getData();
|
||||
mergeObject(formData,
|
||||
{
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
effects: this.actor.effects.map(e => foundry.utils.deepClone(e)),
|
||||
limited: this.actor.limited,
|
||||
owner: this.actor.isOwner,
|
||||
biographie: await TextEditor.enrichHTML(this.actor.system.biographie, { async: true }),
|
||||
notes: await TextEditor.enrichHTML(this.actor.system.notes, { async: true }),
|
||||
});
|
||||
mergeObject(formData.calc, {
|
||||
foundry.utils.mergeObject(formData, {
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
limited: this.actor.limited,
|
||||
owner: this.actor.isOwner,
|
||||
biographie: await RdDTextEditor.enrichHTML(this.actor.system.biographie, this.actor),
|
||||
notes: await RdDTextEditor.enrichHTML(this.actor.system.notes, this.actor),
|
||||
});
|
||||
foundry.utils.mergeObject(formData.calc, {
|
||||
surenc: this.actor.computeMalusSurEncombrement(),
|
||||
surprise: RdDBonus.find(this.actor.getSurprise(false)).descr,
|
||||
resumeBlessures: this.actor.computeResumeBlessure(this.actor.system.blessures),
|
||||
caracTotal: RdDCarac.computeTotal(this.actor.system.carac, this.actor.system.beaute),
|
||||
surEncombrementMessage: this.actor.getMessageSurEncombrement(),
|
||||
surEncombrementMessage: this.actor.isSurenc() ? "Sur-Encombrement!" : "",
|
||||
malusArmure: this.actor.getMalusArmure()
|
||||
})
|
||||
|
||||
this.timerRecherche = undefined;
|
||||
@ -79,10 +78,13 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
||||
});
|
||||
|
||||
// toujours avoir une liste d'armes (pour mettre esquive et corps à corps)
|
||||
formData.combat = duplicate(formData.armes ?? []);
|
||||
const actor = this.actor;
|
||||
formData.combat = foundry.utils.duplicate(formData.armes);
|
||||
RdDItemArme.computeNiveauArmes(formData.combat, formData.competences);
|
||||
RdDItemArme.ajoutCorpsACorps(formData.combat, formData.competences, formData.system.carac);
|
||||
formData.esquives = this.actor.getCompetences("Esquive");
|
||||
formData.combat.push(RdDItemArme.corpsACorps(actor));
|
||||
formData.combat.push(RdDItemArme.empoignade(actor));
|
||||
|
||||
formData.esquives = this.actor.getCompetencesEsquive()
|
||||
formData.combat = RdDCombatManager.listActionsArmes(formData.combat, formData.competences, formData.system.carac);
|
||||
formData.empoignades = this.actor.getEmpoignades();
|
||||
|
||||
@ -97,6 +99,7 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
||||
cacheTMR: this.actor.isTMRCache()
|
||||
}
|
||||
|
||||
formData.race = actor.itemTypes[ITEM_TYPES.race].find(it => true)
|
||||
formData.subacteurs = {
|
||||
vehicules: this.actor.listeVehicules(),
|
||||
montures: this.actor.listeMontures(),
|
||||
@ -110,62 +113,59 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
||||
return formData;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */ /** @override */
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
HtmlUtility.showControlWhen(this.html.find(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue"));
|
||||
HtmlUtility.showControlWhen(this.html.find(".appliquerFatigue"), ReglesOptionnelles.isUsing("appliquer-fatigue"));
|
||||
|
||||
this.html.find('.subacteur-open').click(async event => {
|
||||
const subActorId = RdDSheetUtility.getEventItemData(event, 'subactor-id');
|
||||
this.openSubActeur(subActorId);
|
||||
})
|
||||
|
||||
this.html.find('.show-hide-competences').click(async event => {
|
||||
this.options.showCompNiveauBase = !this.options.showCompNiveauBase;
|
||||
this.render(true);
|
||||
});
|
||||
|
||||
this.html.find('.button-tmr-visu').click(async event => this.actor.displayTMR("visu"))
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
this.html.find('.item-action').click(async event => {
|
||||
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||
item?.actionPrincipale(this.actor, async () => this.render())
|
||||
});
|
||||
|
||||
this.html.find('.subacteur-delete').click(async event => {
|
||||
const li = RdDSheetUtility.getEventElement(event);
|
||||
const actorId = li.data("actor-id");
|
||||
if (actorId) {
|
||||
const subActor = game.actors.get(actorId);
|
||||
RdDUtility.confirmerSuppressionSubacteur(this, subActor, li);
|
||||
}
|
||||
});
|
||||
this.html.find('.experiencelog-delete').click(async event => {
|
||||
const li = this.html.find(event.currentTarget)?.parents(".experiencelog");
|
||||
const key = Number(li.data("key") ?? -1);
|
||||
await this.actor.deleteExperienceLog(key, 1);
|
||||
});
|
||||
this.html.find('.experiencelog-delete-previous').click(async event => {
|
||||
const li = this.html.find(event.currentTarget)?.parents(".experiencelog");
|
||||
const key = Number(li.data("key") ?? -1);
|
||||
await this.actor.deleteExperienceLog(0, key + 1);
|
||||
});
|
||||
this.html.find('.encaisser-direct').click(async event => {
|
||||
this.actor.encaisser();
|
||||
})
|
||||
this.html.find('.sheet-possession-attack').click(async event => {
|
||||
const poss = RdDSheetUtility.getItem(event, this.actor)
|
||||
this.actor.conjurerPossession(poss)
|
||||
})
|
||||
this.html.find('.remise-a-neuf').click(async event => {
|
||||
if (game.user.isGM) {
|
||||
this.actor.remiseANeuf();
|
||||
}
|
||||
|
||||
this.html.find('.subacteur-coeur-toggle a').click(async event => {
|
||||
const subActorIdactorId = RdDSheetUtility.getEventItemData(event, 'subactor-id')
|
||||
const coeurNombre = $(event.currentTarget).data('numero-coeur')
|
||||
RdDCoeur.toggleSubActeurCoeur(this.actor.id, subActorIdactorId, coeurNombre)
|
||||
})
|
||||
this.html.find('.subacteur-tendre-moment').click(async event => {
|
||||
const subActorId = RdDSheetUtility.getEventItemData(event, 'subactor-id')
|
||||
RdDCoeur.startSubActeurTendreMoment(this.actor.id, subActorId)
|
||||
})
|
||||
this.html.find('.subacteur-delete').click(async event => {
|
||||
const li = RdDSheetUtility.getEventElement(event);
|
||||
const subActorId = li.data("subactor-id");
|
||||
this.deleteSubActeur(subActorId, li);
|
||||
})
|
||||
this.html.find("input.derivee-value[name='system.compteurs.stress.value']").change(async event => {
|
||||
this.actor.updateCompteurValue("stress", parseInt(event.target.value));
|
||||
});
|
||||
this.html.find('.creer-tache').click(async event => {
|
||||
this.createEmptyTache();
|
||||
this.html.find("input.derivee-value[name='system.compteurs.experience.value']").change(async event => {
|
||||
this.actor.updateCompteurValue("experience", parseInt(event.target.value));
|
||||
});
|
||||
|
||||
this.html.find('.creer-tache').click(async event => this.createEmptyTache());
|
||||
this.html.find('.creer-une-oeuvre').click(async event => this.selectTypeOeuvreToCreate());
|
||||
this.html.find('.creer-tache-blessure-legere').click(async event => RdDItemBlessure.createTacheSoinBlessure(this.actor, 2));
|
||||
this.html.find('.creer-tache-blessure-grave').click(async event => RdDItemBlessure.createTacheSoinBlessure(this.actor, 4));
|
||||
this.html.find('.creer-tache-blessure-critique').click(async event => RdDItemBlessure.createTacheSoinBlessure(this.actor, 6));
|
||||
this.html.find('.creer-blessure-legere').click(async event => RdDItemBlessure.createBlessure(this.actor, 2));
|
||||
this.html.find('.creer-blessure-grave').click(async event => RdDItemBlessure.createBlessure(this.actor, 4));
|
||||
this.html.find('.creer-blessure-critique').click(async event => RdDItemBlessure.createBlessure(this.actor, 6));
|
||||
this.html.find('.creer-une-oeuvre').click(async event => {
|
||||
this.selectTypeOeuvreToCreate();
|
||||
});
|
||||
|
||||
this.html.find('.blessure-premierssoins-done').change(async event => {
|
||||
const blessure = this.getBlessure(event);
|
||||
@ -184,252 +184,114 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
||||
await blessure?.setSoinsBlessure({ soinscomplets: { bonus: Number(event.currentTarget.value) } })
|
||||
});
|
||||
|
||||
// Equip Inventory Item
|
||||
this.html.find('.item-equip').click(async event => {
|
||||
this.actor.equiperObjet(RdDSheetUtility.getItemId(event));
|
||||
});
|
||||
this.html.find('.roll-chance-actuelle').click(async event => this.actor.rollCarac('chance-actuelle'))
|
||||
this.html.find('.button-appel-chance').click(async event => this.actor.rollAppelChance())
|
||||
|
||||
// Roll Carac
|
||||
this.html.find('.carac-label a').click(async event => {
|
||||
let caracName = event.currentTarget.attributes.name.value;
|
||||
this.actor.rollCarac(caracName.toLowerCase());
|
||||
});
|
||||
this.html.find('[name="jet-astrologie"]').click(async event => this.actor.astrologieNombresAstraux())
|
||||
this.html.find('.action-tache').click(async event => this.actor.rollTache(RdDSheetUtility.getItemId(event)))
|
||||
this.html.find('.meditation-label a').click(async event => this.actor.rollMeditation(RdDSheetUtility.getItemId(event)))
|
||||
|
||||
this.html.find('.chance-actuelle').click(async event => {
|
||||
this.actor.rollCarac('chance-actuelle');
|
||||
});
|
||||
this.html.find('.action-chant').click(async event => this.actor.rollChant(RdDSheetUtility.getItemId(event)))
|
||||
this.html.find('.action-danse').click(async event => this.actor.rollDanse(RdDSheetUtility.getItemId(event)))
|
||||
this.html.find('.action-musique').click(async event => this.actor.rollMusique(RdDSheetUtility.getItemId(event)))
|
||||
this.html.find('.action-oeuvre').click(async event => this.actor.rollOeuvre(RdDSheetUtility.getItemId(event)))
|
||||
this.html.find('.action-jeu').click(async event => this.actor.rollJeu(RdDSheetUtility.getItemId(event)))
|
||||
this.html.find('.action-recettecuisine').click(async event => this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event)))
|
||||
|
||||
this.html.find('.chance-appel').click(async event => {
|
||||
this.actor.rollAppelChance();
|
||||
});
|
||||
|
||||
this.html.find('[name="jet-astrologie"]').click(async event => {
|
||||
this.actor.astrologieNombresAstraux();
|
||||
});
|
||||
|
||||
// Roll Skill
|
||||
this.html.find('a.competence-label').click(async event => {
|
||||
this.actor.rollCompetence(RdDSheetUtility.getItemId(event));
|
||||
});
|
||||
this.html.find('.tache-label a').click(async event => {
|
||||
this.actor.rollTache(RdDSheetUtility.getItemId(event));
|
||||
});
|
||||
this.html.find('.meditation-label a').click(async event => {
|
||||
this.actor.rollMeditation(RdDSheetUtility.getItemId(event));
|
||||
});
|
||||
this.html.find('.chant-label a').click(async event => {
|
||||
this.actor.rollChant(RdDSheetUtility.getItemId(event));
|
||||
});
|
||||
this.html.find('.danse-label a').click(async event => {
|
||||
this.actor.rollDanse(RdDSheetUtility.getItemId(event));
|
||||
});
|
||||
this.html.find('.musique-label a').click(async event => {
|
||||
this.actor.rollMusique(RdDSheetUtility.getItemId(event));
|
||||
});
|
||||
this.html.find('.oeuvre-label a').click(async event => {
|
||||
this.actor.rollOeuvre(RdDSheetUtility.getItemId(event));
|
||||
});
|
||||
this.html.find('.jeu-label a').click(async event => {
|
||||
this.actor.rollJeu(RdDSheetUtility.getItemId(event));
|
||||
});
|
||||
this.html.find('.recettecuisine-label a').click(async event => {
|
||||
this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event));
|
||||
});
|
||||
this.html.find('.subacteur-label a').click(async event => {
|
||||
let actorId = RdDSheetUtility.getEventItemData(event, 'actor-id');
|
||||
let actor = game.actors.get(actorId);
|
||||
if (actor) {
|
||||
actor.sheet.render(true);
|
||||
}
|
||||
});
|
||||
|
||||
// Boutons spéciaux MJs
|
||||
this.html.find('.forcer-tmr-aleatoire').click(async event => {
|
||||
this.actor.reinsertionAleatoire("Action MJ");
|
||||
});
|
||||
this.html.find('.afficher-tmr').click(async event => {
|
||||
this.actor.changeTMRVisible();
|
||||
});
|
||||
this.html.find('.description-aleatoire').click(async event => new AppPersonnageAleatoire(this.actor).render(true))
|
||||
if (game.user.isGM) {
|
||||
// experience log
|
||||
this.html.find('.experiencelog-delete').click(async event => {
|
||||
const li = this.html.find(event.currentTarget)?.parents(".experiencelog");
|
||||
const key = Number(li.data("key") ?? -1);
|
||||
await this.actor.deleteExperienceLog(key, 1);
|
||||
});
|
||||
this.html.find('.experiencelog-delete-previous').click(async event => {
|
||||
const li = this.html.find(event.currentTarget)?.parents(".experiencelog");
|
||||
const key = Number(li.data("key") ?? -1);
|
||||
await this.actor.deleteExperienceLog(0, key + 1);
|
||||
});
|
||||
// Boutons spéciaux MJs
|
||||
this.html.find('.forcer-tmr-aleatoire').click(async event => this.actor.reinsertionAleatoire("Action MJ"))
|
||||
this.html.find('.don-de-haut-reve').click(async event => this.actor.addDonDeHautReve())
|
||||
this.html.find('.afficher-tmr').click(async event => this.actor.changeTMRVisible())
|
||||
}
|
||||
|
||||
// Points de reve actuel
|
||||
this.html.find('.ptreve-actuel a').click(async event => {
|
||||
this.actor.rollCarac('reve-actuel', true);
|
||||
});
|
||||
this.html.find('.roll-reve-actuel').click(async event => this.actor.rollCarac('reve-actuel', {resistance:true}))
|
||||
this.html.find('.action-empoignade').click(async event => RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor)))
|
||||
|
||||
this.html.find('.roll-arme').click(async event => this.actor.rollArme(foundry.utils.duplicate(this._getEventArmeCombat(event)), 'competence'))
|
||||
|
||||
// Suite empoignade
|
||||
this.html.find('.empoignade-label a').click(async event => {
|
||||
let emp = RdDSheetUtility.getItem(event, this.actor)
|
||||
RdDEmpoignade.onAttaqueEmpoignadeFromItem(emp)
|
||||
});
|
||||
// Roll Weapon1
|
||||
this.html.find('.arme-label a').click(async event => {
|
||||
let arme = this._getEventArmeCombat(event);
|
||||
this.actor.rollArme(duplicate(arme));
|
||||
});
|
||||
// Initiative pour l'arme
|
||||
this.html.find('.arme-initiative a').click(async event => {
|
||||
let combatant = game.combat.combatants.find(c => c.actor.id == this.actor.id);
|
||||
this.html.find('.roll-init-arme').click(async event => {
|
||||
let combatant = game.combat.combatants.find(c => c.actor.id == this.actor.id)
|
||||
if (combatant) {
|
||||
let action = this._getEventArmeCombat(event);
|
||||
RdDCombatManager.rollInitiativeAction(combatant._id, action);
|
||||
RdDCombatManager.rollInitiativeAction(combatant._id, this._getEventArmeCombat(event));
|
||||
} else {
|
||||
ui.notifications.info("Impossible de lancer l'initiative sans être dans un combat.");
|
||||
}
|
||||
});
|
||||
// Display TMR, visualisation
|
||||
this.html.find('.visu-tmr').click(async event => {
|
||||
this.actor.displayTMR("visu");
|
||||
});
|
||||
})
|
||||
// Display TMR
|
||||
|
||||
// Display TMR, normal
|
||||
this.html.find('.monte-tmr').click(async event => {
|
||||
this.actor.displayTMR("normal");
|
||||
});
|
||||
this.html.find('.button-tmr').click(async event => this.actor.displayTMR("normal"))
|
||||
this.html.find('.button-tmr-rapide').click(async event => this.actor.displayTMR("rapide"))
|
||||
|
||||
// Display TMR, fast
|
||||
this.html.find('.monte-tmr-rapide').click(async event => {
|
||||
this.actor.displayTMR("rapide");
|
||||
});
|
||||
this.html.find('.button-repos').click(async event => await this.actor.repos())
|
||||
|
||||
this.html.find('.repos').click(async event => {
|
||||
await this.actor.repos();
|
||||
});
|
||||
this.html.find('.delete-active-effect').click(async event => {
|
||||
if (game.user.isGM) {
|
||||
let effect = this.html.find(event.currentTarget).parents(".active-effect").data('effect');
|
||||
this.actor.removeEffect(effect);
|
||||
}
|
||||
});
|
||||
this.html.find('.enlever-tous-effets').click(async event => {
|
||||
if (game.user.isGM) {
|
||||
await this.actor.removeEffects();
|
||||
}
|
||||
});
|
||||
this.html.find('.carac-xp-augmenter').click(async event => {
|
||||
let caracName = event.currentTarget.name.replace("augmenter.", "");
|
||||
this.actor.updateCaracXPAuto(caracName);
|
||||
});
|
||||
this.html.find('.competence-xp-augmenter').click(async event => {
|
||||
this.actor.updateCompetenceXPAuto(RdDSheetUtility.getItemId(event));
|
||||
});
|
||||
this.html.find('.competence-stress-augmenter').click(async event => {
|
||||
this.actor.updateCompetenceStress(RdDSheetUtility.getItemId(event));
|
||||
});
|
||||
this.html.find('.carac-xp-augmenter').click(async event => this.actor.updateCaracXPAuto(event.currentTarget.name.replace("augmenter.", "")))
|
||||
this.html.find('.competence-xp-augmenter').click(async event => this.actor.updateCompetenceXPAuto(RdDSheetUtility.getItemId(event)))
|
||||
this.html.find('.competence-stress-augmenter').click(async event => this.actor.updateCompetenceStress(RdDSheetUtility.getItemId(event)))
|
||||
|
||||
if (this.options.vueDetaillee) {
|
||||
// On carac change
|
||||
this.html.find('.carac-value').change(async event => {
|
||||
let caracName = event.currentTarget.name.replace(".value", "").replace("system.carac.", "");
|
||||
this.actor.updateCarac(caracName, parseInt(event.target.value));
|
||||
});
|
||||
this.html.find('input.carac-xp').change(async event => {
|
||||
let caracName = event.currentTarget.name.replace(".xp", "").replace("system.carac.", "");
|
||||
this.actor.updateCaracXP(caracName, parseInt(event.target.value));
|
||||
});
|
||||
// On competence change
|
||||
this.html.find('.competence-value').change(async event => {
|
||||
let compName = event.currentTarget.attributes.compname.value;
|
||||
//console.log("Competence changed :", compName);
|
||||
this.actor.updateCompetence(compName, parseInt(event.target.value));
|
||||
});
|
||||
// On competence xp change
|
||||
this.html.find('input.competence-xp').change(async event => {
|
||||
let compName = event.currentTarget.attributes.compname.value;
|
||||
this.actor.updateCompetenceXP(compName, parseInt(event.target.value));
|
||||
});
|
||||
// On competence xp change
|
||||
this.html.find('input.competence-xp-sort').change(async event => {
|
||||
let compName = event.currentTarget.attributes.compname.value;
|
||||
this.actor.updateCompetenceXPSort(compName, parseInt(event.target.value));
|
||||
});
|
||||
|
||||
this.html.find('.toggle-archetype').click(async event => {
|
||||
this.options.vueArchetype = !this.options.vueArchetype;
|
||||
this.render(true);
|
||||
});
|
||||
// On competence archetype change
|
||||
this.html.find('.competence-archetype').change(async event => {
|
||||
let compName = event.currentTarget.attributes.compname.value;
|
||||
this.actor.updateCompetenceArchetype(compName, parseInt(event.target.value));
|
||||
});
|
||||
this.html.find('.nouvelle-incarnation').click(async event => this.actor.nouvelleIncarnation())
|
||||
}
|
||||
|
||||
this.html.find('.show-hide-competences').click(async event => {
|
||||
this.options.showCompNiveauBase = !this.options.showCompNiveauBase;
|
||||
this.render(true);
|
||||
});
|
||||
|
||||
this.html.find('.vue-detaillee').click(async event => {
|
||||
this.options.vueDetaillee = !this.options.vueDetaillee;
|
||||
this.render(true);
|
||||
});
|
||||
|
||||
// On pts de reve change
|
||||
this.html.find('.pointsreve-value').change(async event => {
|
||||
let reveValue = event.currentTarget.value;
|
||||
this.actor.update({ "system.reve.reve.value": reveValue });
|
||||
});
|
||||
this.html.find('.pointsreve-value').change(async event => this.actor.update({ "system.reve.reve.value": event.currentTarget.value }))
|
||||
this.html.find('.seuil-reve-value').change(async event => this.actor.setPointsDeSeuil(event.currentTarget.value))
|
||||
|
||||
// On seuil de reve change
|
||||
this.html.find('.seuil-reve-value').change(async event => {
|
||||
console.log("seuil-reve-value", event.currentTarget)
|
||||
this.actor.setPointsDeSeuil(event.currentTarget.value);
|
||||
});
|
||||
this.html.find('.stress-test').click(async event => this.actor.transformerStress())
|
||||
this.html.find('.moral-malheureux').click(async event => this.actor.jetDeMoral('malheureuse'))
|
||||
this.html.find('.moral-neutre').click(async event => this.actor.jetDeMoral('neutre'))
|
||||
this.html.find('.moral-heureux').click(async event => this.actor.jetDeMoral('heureuse'))
|
||||
this.html.find('.button-ethylisme').click(async event => this.actor.jetEthylisme())
|
||||
|
||||
// On stress change
|
||||
this.html.find('.compteur-edit').change(async event => {
|
||||
let fieldName = event.currentTarget.attributes.name.value;
|
||||
this.actor.updateCompteurValue(fieldName, parseInt(event.target.value));
|
||||
});
|
||||
|
||||
this.html.find('.stress-test').click(async event => {
|
||||
this.actor.transformerStress();
|
||||
});
|
||||
this.html.find('.moral-malheureux').click(async event => {
|
||||
this.actor.jetDeMoral('malheureuse');
|
||||
});
|
||||
this.html.find('.moral-neutre').click(async event => {
|
||||
this.actor.jetDeMoral('neutre');
|
||||
});
|
||||
this.html.find('.moral-heureux').click(async event => {
|
||||
this.actor.jetDeMoral('heureuse');
|
||||
});
|
||||
this.html.find('.ethylisme-test').click(async event => {
|
||||
this.actor.jetEthylisme();
|
||||
});
|
||||
|
||||
this.html.find('.jet-vie').click(async event => {
|
||||
this.actor.jetVie();
|
||||
});
|
||||
this.html.find('.jet-endurance').click(async event => {
|
||||
this.actor.jetEndurance();
|
||||
});
|
||||
|
||||
this.html.find('.vie-plus').click(async event => {
|
||||
this.actor.santeIncDec("vie", 1);
|
||||
});
|
||||
this.html.find('.vie-moins').click(async event => {
|
||||
this.actor.santeIncDec("vie", -1);
|
||||
});
|
||||
this.html.find('.endurance-plus').click(async event => {
|
||||
this.actor.santeIncDec("endurance", 1);
|
||||
});
|
||||
this.html.find('.endurance-moins').click(async event => {
|
||||
this.actor.santeIncDec("endurance", -1);
|
||||
});
|
||||
this.html.find('.ptreve-actuel-plus').click(async event => {
|
||||
this.actor.reveActuelIncDec(1);
|
||||
});
|
||||
this.html.find('.ptreve-actuel-moins').click(async event => {
|
||||
this.actor.reveActuelIncDec(-1);
|
||||
});
|
||||
this.html.find('.fatigue-plus').click(async event => {
|
||||
this.actor.santeIncDec("fatigue", 1);
|
||||
});
|
||||
this.html.find('.fatigue-moins').click(async event => {
|
||||
this.actor.santeIncDec("fatigue", -1);
|
||||
});
|
||||
this.html.find('.ptreve-actuel-plus').click(async event => this.actor.reveActuelIncDec(1))
|
||||
this.html.find('.ptreve-actuel-moins').click(async event => this.actor.reveActuelIncDec(-1))
|
||||
this.html.find('.chance-actuelle-plus').click(async event => this.actor.chanceActuelleIncDec(1))
|
||||
this.html.find('.chance-actuelle-moins').click(async event => this.actor.chanceActuelleIncDec(-1))
|
||||
this.html.find('.fatigue-plus').click(async event => this.actor.santeIncDec("fatigue", 1))
|
||||
this.html.find('.fatigue-moins').click(async event => this.actor.santeIncDec("fatigue", -1))
|
||||
}
|
||||
|
||||
getBlessure(event) {
|
||||
const itemId = this.html.find(event.currentTarget).parents(".item-blessure").data('item-id');
|
||||
const blessure = this.actor.getItem(itemId, 'blessure');
|
||||
return blessure;
|
||||
const blessureId = this.html.find(event.currentTarget).parents(".item-blessure").data('item-id');
|
||||
return this.actor.getItem(blessureId, 'blessure');
|
||||
}
|
||||
|
||||
isCompetenceAffichable(competence) {
|
||||
@ -443,11 +305,26 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
||||
super._onDropActor(event, dragData);
|
||||
}
|
||||
|
||||
openSubActeur(actorId) {
|
||||
game.actors.get(actorId)?.sheet.render(true)
|
||||
}
|
||||
|
||||
deleteSubActeur(actorId, li) {
|
||||
if (actorId) {
|
||||
const subActor = game.actors.get(actorId);
|
||||
RdDUtility.confirmSubActeurDelete(this, subActor, li, () => {
|
||||
console.log('Delete : ', subActor.id);
|
||||
this.actor.deleteSubActeur(subActor.id);
|
||||
RdDUtility.slideOnDelete(this, li);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async selectTypeOeuvreToCreate() {
|
||||
let typeObjets = RdDItem.getTypesOeuvres();
|
||||
let content = `<span class="competence-label">Selectionnez le type d'oeuvre</span><select class="item-type">`;
|
||||
for (let typeName of typeObjets) {
|
||||
let types = RdDItem.getTypesOeuvres();
|
||||
let content = `<span class="generic-label">Selectionnez le type d'oeuvre</span><select class="item-type">`;
|
||||
for (let typeName of types) {
|
||||
content += `<option value="${typeName}">${Misc.typeName('Item', typeName)}</option>`
|
||||
}
|
||||
content += '</select>';
|
||||
@ -512,7 +389,7 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
||||
async _onSplitItem(item, split) {
|
||||
if (split >= 1 && split < item.system.quantite) {
|
||||
await item.diminuerQuantite(split);
|
||||
const splitItem = duplicate(item);
|
||||
const splitItem = foundry.utils.duplicate(item);
|
||||
splitItem.system.quantite = split;
|
||||
await this.actor.createEmbeddedDocuments('Item', [splitItem])
|
||||
}
|
||||
|
2440
module/actor.js
70
module/actor/base-actor-reve-sheet.js
Normal file
@ -0,0 +1,70 @@
|
||||
import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js";
|
||||
import { Grammar } from "../grammar.js";
|
||||
import { ITEM_TYPES } from "../constants.js";
|
||||
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
|
||||
import { RdDBaseActorSheet } from "./base-actor-sheet.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
* @extends {ActorSheet}
|
||||
*/
|
||||
export class RdDBaseActorReveSheet extends RdDBaseActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(RdDBaseActorSheet.defaultOptions, {
|
||||
width: 550
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
this.html.find('.button-encaissement').click(async event => this.actor.encaisser())
|
||||
this.html.find('.roll-carac').click(async event => {
|
||||
this.actor.rollCarac(Grammar.toLowerCaseNoAccent(event.currentTarget.attributes['data-carac-name'].value))})
|
||||
this.html.find('.roll-competence').click(async event => this.actor.rollCompetence(RdDSheetUtility.getItemId(event)));
|
||||
this.html.find('.endurance-plus').click(async event => this.actor.santeIncDec("endurance", 1));
|
||||
this.html.find('.endurance-moins').click(async event => this.actor.santeIncDec("endurance", -1));
|
||||
|
||||
if (game.user.isGM) {
|
||||
this.html.find('.button-remise-a-neuf').click(async event => this.actor.remiseANeuf())
|
||||
this.html.find('.delete-active-effect').click(async event => this.actor.removeEffect(this.html.find(event.currentTarget).parents(".active-effect").data('effect')));
|
||||
this.html.find('.enlever-tous-effets').click(async event => await this.actor.removeEffects());
|
||||
}
|
||||
this.html.find('.competence-add').click(async event =>
|
||||
await this.actor.createEmbeddedDocuments("Item", [{
|
||||
type: ITEM_TYPES.competencecreature,
|
||||
name: 'Nouvelle competence',
|
||||
img: 'systems/foundryvtt-reve-de-dragon/icons/compcreature-serres.webp',
|
||||
system: {
|
||||
carac_value: this.actor.getForce(),
|
||||
}
|
||||
}], { renderSheet: true })
|
||||
)
|
||||
this.html.find('.roll-text').click(async event => await RdDTextEditor.rollText(event, this.actor))
|
||||
this.html.find('.chat-roll-text').click(async event => await RdDTextEditor.chatRollText(event))
|
||||
|
||||
|
||||
if (this.options.vueDetaillee) {
|
||||
// On carac change
|
||||
this.html.find('.carac-value').change(async event => {
|
||||
let caracName = event.currentTarget.name.replace(".value", "").replace("system.carac.", "");
|
||||
this.actor.updateCarac(caracName, parseInt(event.target.value));
|
||||
});
|
||||
// On competence change
|
||||
this.html.find('.competence-value').change(async event => {
|
||||
let compName = event.currentTarget.attributes.compname.value;
|
||||
//console.log("Competence changed :", compName);
|
||||
this.actor.updateCompetence(compName, parseInt(event.target.value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
578
module/actor/base-actor-reve.js
Normal file
@ -0,0 +1,578 @@
|
||||
import { ENTITE_INCARNE, SHOW_DICE, SYSTEM_RDD } from "../constants.js";
|
||||
import { Grammar } from "../grammar.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { RdDResolutionTable } from "../rdd-resolution-table.js";
|
||||
import { RdDEncaisser } from "../rdd-roll-encaisser.js";
|
||||
import { RdDRoll } from "../rdd-roll.js";
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
|
||||
import { RdDBaseActor } from "./base-actor.js";
|
||||
import { ITEM_TYPES } from "../constants.js";
|
||||
import { RdDItemCompetence } from "../item-competence.js";
|
||||
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
|
||||
import { RdDItemArme } from "../item-arme.js";
|
||||
import { StatusEffects } from "../settings/status-effects.js";
|
||||
import { Targets } from "../targets.js";
|
||||
import { RdDConfirm } from "../rdd-confirm.js";
|
||||
import { RdDCarac } from "../rdd-carac.js";
|
||||
|
||||
import { ChatUtility } from "../chat-utility.js";
|
||||
import { DialogValidationEncaissement } from "../dialog-validation-encaissement.js";
|
||||
import { RdDCombat } from "../rdd-combat.js";
|
||||
import { RdDEmpoignade } from "../rdd-empoignade.js";
|
||||
import { RdDPossession } from "../rdd-possession.js";
|
||||
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, POSSESSION_SANS_DRACONIC } from "../item/base-items.js";
|
||||
import { RollDataAjustements } from "../rolldata-ajustements.js";
|
||||
|
||||
/**
|
||||
* Classe de base pour les acteurs disposant de rêve (donc, pas des objets)
|
||||
* - Entités de rêve
|
||||
* - Créatures de "sang": créatures et humanoides
|
||||
*/
|
||||
export class RdDBaseActorReve extends RdDBaseActor {
|
||||
|
||||
prepareActorData() {
|
||||
super.prepareActorData()
|
||||
this.system.attributs.plusdom.value = this.getBonusDegat()
|
||||
this.system.sante.endurance.max = this.getEnduranceMax()
|
||||
this.system.sante.endurance.value = Math.min(this.system.sante.endurance.value, this.system.sante.endurance.max)
|
||||
}
|
||||
|
||||
getCarac() {
|
||||
return foundry.utils.mergeObject(this.system.carac,
|
||||
{
|
||||
'reve-actuel': this.getCaracReveActuel(),
|
||||
'chance-actuelle': this.getCaracChanceActuelle()
|
||||
},
|
||||
{ inplace: false })
|
||||
}
|
||||
|
||||
getCaracChanceActuelle() {
|
||||
return {
|
||||
label: 'Chance actuelle',
|
||||
value: this.getChanceActuel(),
|
||||
type: "number"
|
||||
};
|
||||
}
|
||||
|
||||
getCaracReveActuel() {
|
||||
return {
|
||||
label: 'Rêve actuel',
|
||||
value: this.getReveActuel(),
|
||||
type: "number"
|
||||
};
|
||||
}
|
||||
|
||||
getTaille() { return Misc.toInt(this.system.carac.taille?.value) }
|
||||
getConstitution() { return this.getReve() }
|
||||
getForce() { return this.getReve() }
|
||||
getAgilite() { return this.getForce() }
|
||||
getReve() { return Misc.toInt(this.system.carac.reve?.value) }
|
||||
getChance() { return this.getReve() }
|
||||
|
||||
getReveActuel() { return this.getReve() }
|
||||
getChanceActuel() { return this.getChance() }
|
||||
|
||||
getEnduranceMax() { return Math.max(1, this.getTaille() + this.getConstitution()) }
|
||||
getEncombrementMax() { return (this.getForce() + this.getTaille()) / 2 }
|
||||
getBonusDegat() { return RdDCarac.getCaracDerivee(this.getEncombrementMax()).plusdom }
|
||||
|
||||
getMoralTotal() { return 0 }
|
||||
getProtectionNaturelle() { return Number(this.system.attributs?.protection?.value ?? 0) }
|
||||
getSConst() { return 0 }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
isSurenc() { return false }
|
||||
computeMalusSurEncombrement() { return 0 }
|
||||
|
||||
ajustementAstrologique() { return 0 }
|
||||
getMalusArmure() { return 0 }
|
||||
|
||||
getEnduranceActuelle() {
|
||||
return Number(this.system.sante?.endurance?.value ?? 0);
|
||||
}
|
||||
async jetEndurance(resteEndurance = undefined) { return { jetEndurance: 0, sonne: false } }
|
||||
isDead() { return false }
|
||||
isSonne() { return false }
|
||||
blessuresASoigner() { return [] }
|
||||
getEtatGeneral(options = { ethylisme: false }) { return 0 }
|
||||
isActorCombat() { return true }
|
||||
|
||||
getCaracInit(competence) {
|
||||
if (!competence) {
|
||||
return 0
|
||||
}
|
||||
if (competence.type == ITEM_TYPES.competencecreature) {
|
||||
return competence.system.carac_value
|
||||
}
|
||||
return this.system.carac[competence.system.defaut_carac].value;
|
||||
}
|
||||
listActionsCombat() {
|
||||
return this.itemTypes[ITEM_TYPES.competencecreature]
|
||||
.filter(it => RdDItemCompetenceCreature.isAttaque(it))
|
||||
.map(it => RdDItemCompetenceCreature.armeCreature(it))
|
||||
.filter(it => it != undefined);
|
||||
}
|
||||
|
||||
|
||||
async computeArmure(attackerRoll) { return this.getProtectionNaturelle() }
|
||||
async remiseANeuf() { }
|
||||
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { }
|
||||
|
||||
async santeIncDec(name, inc, isCritique = false) { }
|
||||
|
||||
async finDeRound(options = { terminer: false }) {
|
||||
await this.$finDeRoundSuppressionEffetsTermines(options);
|
||||
await this.finDeRoundBlessures();
|
||||
await this.$finDeRoundSupprimerObsoletes();
|
||||
await this.$finDeRoundEmpoignade();
|
||||
}
|
||||
|
||||
async $finDeRoundSuppressionEffetsTermines(options) {
|
||||
for (let effect of this.getEffects()) {
|
||||
if (effect.duration.type !== 'none' && (effect.duration.remaining <= 0 || options.terminer)) {
|
||||
await effect.delete();
|
||||
ChatMessage.create({ content: `${this.getAlias()} n'est plus ${Misc.lowerFirst(game.i18n.localize(effect.system.label))} !` });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async finDeRoundBlessures() {
|
||||
}
|
||||
|
||||
async $finDeRoundSupprimerObsoletes() {
|
||||
const obsoletes = []
|
||||
.concat(this.itemTypes[ITEM_TYPES.empoignade].filter(it => it.system.pointsemp <= 0))
|
||||
.concat(this.itemTypes[ITEM_TYPES.possession].filter(it => it.system.compteur < -2 || it.system.compteur > 2))
|
||||
.map(it => it.id);
|
||||
await this.deleteEmbeddedDocuments('Item', obsoletes);
|
||||
}
|
||||
|
||||
async $finDeRoundEmpoignade() {
|
||||
const immobilisations = this.itemTypes[ITEM_TYPES.empoignade].filter(it => it.system.pointsemp >= 2 && it.system.empoigneurid == this.id);
|
||||
immobilisations.forEach(emp => RdDEmpoignade.onImmobilisation(this,
|
||||
game.actors.get(emp.system.empoigneid),
|
||||
emp
|
||||
))
|
||||
}
|
||||
|
||||
async setSonne(sonne = true) { }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getCompetence(idOrName, options = {}) {
|
||||
if (idOrName instanceof Item) {
|
||||
return idOrName.isCompetence() ? idOrName : undefined
|
||||
}
|
||||
return RdDItemCompetence.findCompetence(this.items, idOrName, options)
|
||||
}
|
||||
|
||||
getCompetences(name, options = { onMessage: message => { } }) {
|
||||
return RdDItemCompetence.findCompetences(this.items, name, options)
|
||||
}
|
||||
|
||||
getCompetenceCorpsACorps(options = { onMessage: message => { } }) {
|
||||
return this.getCompetence(BASE_CORPS_A_CORPS.name, options) ?? BASE_CORPS_A_CORPS
|
||||
}
|
||||
|
||||
getCompetencesEsquive(options = { onMessage: message => { } }) {
|
||||
return this.getCompetences(BASE_ESQUIVE.name, options) ?? [BASE_ESQUIVE]
|
||||
}
|
||||
|
||||
getArmeParade(armeParadeId) {
|
||||
return RdDItemArme.getArme(armeParadeId ? this.getEmbeddedDocument('Item', armeParadeId) : undefined)
|
||||
}
|
||||
|
||||
getDraconicOuPossession() { return POSSESSION_SANS_DRACONIC }
|
||||
|
||||
getPossession(possessionId) {
|
||||
return this.itemTypes[ITEM_TYPES.possession].find(it => it.system.possessionid == possessionId);
|
||||
}
|
||||
getEmpoignades() {
|
||||
return this.itemTypes[ITEM_TYPES.empoignade];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async updateCreatureCompetence(idOrName, fieldName, value) {
|
||||
let competence = this.getCompetence(idOrName);
|
||||
if (competence) {
|
||||
function getFieldPath(fieldName) {
|
||||
switch (fieldName) {
|
||||
case "niveau": return 'system.niveau';
|
||||
case "dommages": return 'system.dommages';
|
||||
case "carac_value": return 'system.carac_value';
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
const path = getFieldPath(fieldName);
|
||||
if (path) {
|
||||
await competence.update({ [path]: value });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
isEffectAllowed(effectId) { return false }
|
||||
|
||||
getEffects(filter = e => true) {
|
||||
return this.getEmbeddedCollection("ActiveEffect").filter(filter);
|
||||
}
|
||||
|
||||
getEffect(effectId) {
|
||||
return this.getEmbeddedCollection("ActiveEffect").find(it => it.statuses?.has(effectId));
|
||||
}
|
||||
|
||||
async setEffect(effectId, status) {
|
||||
if (this.isEffectAllowed(effectId)) {
|
||||
const effect = this.getEffect(effectId);
|
||||
if (!status && effect) {
|
||||
await this.deleteEmbeddedDocuments('ActiveEffect', [effect.id]);
|
||||
}
|
||||
if (status && !effect) {
|
||||
await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(effectId)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async removeEffect(id) {
|
||||
const effect = this.getEmbeddedCollection("ActiveEffect").find(it => it.id == id);
|
||||
if (effect) {
|
||||
await this.deleteEmbeddedDocuments('ActiveEffect', [id]);
|
||||
}
|
||||
}
|
||||
|
||||
async removeEffects(filter = e => true) {
|
||||
if (game.user.isGM) {
|
||||
const ids = this.getEffects(filter).map(it => it.id);
|
||||
await this.deleteEmbeddedDocuments('ActiveEffect', ids);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getSurprise(isCombat = undefined) {
|
||||
let niveauSurprise = this.getEffects()
|
||||
.map(effect => StatusEffects.valeurSurprise(effect, isCombat))
|
||||
.reduce(Misc.sum(), 0);
|
||||
if (niveauSurprise > 1) {
|
||||
return 'totale';
|
||||
}
|
||||
if (niveauSurprise == 1) {
|
||||
return 'demi';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async computeEtatGeneral() {
|
||||
// Par défaut, on ne calcule pas d'état général, seuls les personnages/créatures sont affectés
|
||||
this.system.compteurs.etat.value = 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async openRollDialog({ name, label, template, rollData, callbackAction }) {
|
||||
const dialog = await RdDRoll.create(this, rollData,
|
||||
{ html: template, close: async html => await this._onCloseRollDialog(html) },
|
||||
{
|
||||
name: name,
|
||||
label: label,
|
||||
callbacks: [
|
||||
this.createCallbackExperience(),
|
||||
this.createCallbackAppelAuMoral(),
|
||||
{ action: callbackAction }
|
||||
]
|
||||
});
|
||||
dialog.render(true);
|
||||
return dialog
|
||||
}
|
||||
|
||||
createEmptyCallback() {
|
||||
return {
|
||||
condition: r => false,
|
||||
action: r => { }
|
||||
};
|
||||
}
|
||||
createCallbackExperience() { return this.createEmptyCallback(); }
|
||||
createCallbackAppelAuMoral() { return this.createEmptyCallback(); }
|
||||
async _onCloseRollDialog(html) { }
|
||||
|
||||
async rollCaracCompetence(caracName, compName, diff, options = { title: "" }) {
|
||||
RdDEmpoignade.checkEmpoignadeEnCours(this)
|
||||
const competence = this.getCompetence(compName);
|
||||
await this.openRollDialog({
|
||||
name: 'jet-competence',
|
||||
label: competence? 'Jet ' + Grammar.apostrophe('de', competence.name) : `Jet sans compétence (${compName})`,
|
||||
template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html',
|
||||
rollData: {
|
||||
alias: this.getAlias(),
|
||||
carac: this.system.carac,
|
||||
selectedCarac: this.getCaracByName(caracName),
|
||||
selectedCaracName: caracName,
|
||||
diffLibre: diff,
|
||||
competence: competence,
|
||||
show: { title: options?.title ?? '' }
|
||||
},
|
||||
callbackAction: r => this.$onRollCompetence(r, options)
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Méthode pour faire un jet prédéterminer sans ouvrir la fenêtre de dialogue
|
||||
* @param {*} caracName code ou label de la caractéristique. On peut utiliser 'intel' pour Intellect.
|
||||
* @param {*} compName nom de compétence ou nom abrégé.
|
||||
* @param {*} diff difficulté (0 si undefined)
|
||||
* @param {*} options
|
||||
* @returns le jet effectué
|
||||
*/
|
||||
async doRollCaracCompetence(caracName, compName, diff, options = { title: "" }) {
|
||||
const carac = this.getCaracByName(caracName);
|
||||
if (!carac) {
|
||||
ui.notifications.warn(`${this.name} n'a pas de caractéristique correspondant à ${caracName}`)
|
||||
return
|
||||
}
|
||||
const competence = this.getCompetence(compName);
|
||||
let rollData = {
|
||||
alias: this.getAlias(),
|
||||
caracValue: Number(carac.value),
|
||||
selectedCarac: carac,
|
||||
competence: competence,
|
||||
diffLibre: diff ?? 0,
|
||||
show: { title: options?.title ?? '' }
|
||||
}
|
||||
RollDataAjustements.calcul(rollData, this);
|
||||
await RdDResolutionTable.rollData(rollData);
|
||||
this.gererExperience(rollData);
|
||||
await RdDResolutionTable.displayRollData(rollData, this)
|
||||
return rollData.rolled;
|
||||
}
|
||||
|
||||
gererExperience(rollData) { }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async roll() {
|
||||
RdDEmpoignade.checkEmpoignadeEnCours(this)
|
||||
|
||||
const carac = this.getCarac()
|
||||
const selectedCaracName = ['apparence', 'perception', 'force', 'reve'].find(it => carac[it] != undefined)
|
||||
|
||||
await this.openRollDialog({
|
||||
name: `jet-${this.id}`,
|
||||
label: `Jet de ${this.getAlias()}`,
|
||||
template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll.html',
|
||||
rollData: {
|
||||
carac: carac,
|
||||
selectedCarac: carac[selectedCaracName],
|
||||
selectedCaracName: selectedCaracName,
|
||||
competences: this.itemTypes['competence']
|
||||
},
|
||||
callbackAction: r => this.$onRollCaracResult(r)
|
||||
})
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async rollCarac(caracName, options = {}) {
|
||||
if (Grammar.equalsInsensitive(caracName, 'taille')) {
|
||||
return
|
||||
}
|
||||
foundry.utils.mergeObject(options, { resistance: false, diff: 0 }, { overwrite: false })
|
||||
RdDEmpoignade.checkEmpoignadeEnCours(this)
|
||||
let selectedCarac = this.getCaracByName(caracName)
|
||||
console.log("selectedCarac", selectedCarac)
|
||||
await this.openRollDialog({
|
||||
name: 'jet-' + caracName,
|
||||
label: 'Jet ' + Grammar.apostrophe('de', selectedCarac.label),
|
||||
template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-carac.html',
|
||||
rollData: {
|
||||
selectedCarac: selectedCarac,
|
||||
competences: this.itemTypes['competence'],
|
||||
diffLibre: options.diff ?? 0,
|
||||
jetResistance: options.resistance ? caracName : undefined
|
||||
},
|
||||
callbackAction: r => this.$onRollCaracResult(r)
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async $onRollCaracResult(rollData) {
|
||||
// Final chat message
|
||||
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-general.html');
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollCompetence(idOrName, options = { tryTarget: true, arme: undefined }) {
|
||||
RdDEmpoignade.checkEmpoignadeEnCours(this)
|
||||
const competence = this.getCompetence(idOrName);
|
||||
let rollData = { carac: this.system.carac, competence: competence, arme: options.arme }
|
||||
if (competence.type == ITEM_TYPES.competencecreature) {
|
||||
const token = RdDUtility.getSelectedToken(this)
|
||||
const arme = RdDItemCompetenceCreature.armeCreature(competence)
|
||||
if (arme && options.tryTarget && Targets.hasTargets()) {
|
||||
Targets.selectOneTargetToken(target => {
|
||||
if (arme.action == "possession") {
|
||||
RdDPossession.onAttaquePossession(target, this, competence)
|
||||
}
|
||||
else {
|
||||
RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme)
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Transformer la competence de créature
|
||||
RdDItemCompetenceCreature.setRollDataCreature(rollData)
|
||||
}
|
||||
|
||||
await this.openRollDialog({
|
||||
name: 'jet-competence',
|
||||
label: 'Jet ' + Grammar.apostrophe('de', competence.name),
|
||||
template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html',
|
||||
rollData: rollData,
|
||||
callbackAction: r => this.$onRollCompetence(r, options)
|
||||
});
|
||||
}
|
||||
|
||||
async $onRollCompetence(rollData, options) {
|
||||
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-competence.html')
|
||||
if (options?.onRollAutomate) {
|
||||
options.onRollAutomate(rollData);
|
||||
}
|
||||
}
|
||||
|
||||
/** --------------------------------------------
|
||||
* @param {*} arme item d'arme/compétence de créature
|
||||
* @param {*} categorieArme catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession
|
||||
* @returns
|
||||
*/
|
||||
rollArme(arme, categorieArme, token) {
|
||||
token = token ?? RdDUtility.getSelectedToken(this)
|
||||
const compToUse = this.$getCompetenceArme(arme, categorieArme)
|
||||
if (!RdDItemArme.isUtilisable(arme)) {
|
||||
ui.notifications.warn(`Arme inutilisable: ${arme.name} a une résistance de 0 ou moins`)
|
||||
return
|
||||
}
|
||||
if (!Targets.hasTargets()) {
|
||||
RdDConfirm.confirmer({
|
||||
settingConfirmer: "confirmer-combat-sans-cible",
|
||||
content: `<p>Voulez vous faire un jet de ${compToUse} sans choisir de cible valide?
|
||||
<br>Tous les jets de combats devront être gérés à la main
|
||||
</p>`,
|
||||
title: 'Ne pas utiliser les automatisation de combat',
|
||||
buttonLabel: "Pas d'automatisation",
|
||||
onAction: async () => {
|
||||
this.rollCompetence(compToUse, { tryTarget: false, arme: arme })
|
||||
}
|
||||
});
|
||||
return
|
||||
}
|
||||
|
||||
Targets.selectOneTargetToken(target => {
|
||||
if (Targets.isTargetEntite(target)) {
|
||||
ui.notifications.warn(`Vous ne pouvez pas attaquer une entité non incarnée avec votre ${arme.name}!!!!`);
|
||||
return
|
||||
}
|
||||
|
||||
const competence = this.getCompetence(compToUse)
|
||||
if (competence.isCompetencePossession()) {
|
||||
return RdDPossession.onAttaquePossession(target, this, competence);
|
||||
}
|
||||
RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme);
|
||||
})
|
||||
}
|
||||
|
||||
$getCompetenceArme(arme, competenceName) {
|
||||
return RdDItemArme.getCompetenceArme(arme, competenceName)
|
||||
}
|
||||
|
||||
verifierForceMin(item) { }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async encaisser() { await RdDEncaisser.encaisser(this) }
|
||||
|
||||
async encaisserDommages(rollData, attacker = undefined, show = undefined, attackerToken = undefined, defenderToken = undefined) {
|
||||
if (attacker && !await attacker.accorder(this, 'avant-encaissement')) {
|
||||
return;
|
||||
}
|
||||
const armure = await this.computeArmure(rollData);
|
||||
if (ReglesOptionnelles.isUsing('validation-encaissement-gr')) {
|
||||
await this.encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken);
|
||||
}
|
||||
else {
|
||||
const jet = await RdDUtility.jetEncaissement(this, rollData, armure, { showDice: SHOW_DICE });
|
||||
await this.$onEncaissement(jet, show, attackerToken, defenderToken)
|
||||
}
|
||||
}
|
||||
|
||||
async encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken) {
|
||||
if (!game.user.isGM) {
|
||||
RdDBaseActor.remoteActorCall({
|
||||
tokenId: this.token?.id,
|
||||
actorId: this.id,
|
||||
method: 'encaisserDommagesValidationGR', args: [rollData, armure, show, attackerToken, defenderToken]
|
||||
})
|
||||
} else {
|
||||
DialogValidationEncaissement.validerEncaissement(this, rollData, armure,
|
||||
jet => this.$onEncaissement(jet, show, attackerToken, defenderToken));
|
||||
}
|
||||
}
|
||||
|
||||
async $onEncaissement(jet, show, attackerToken, defenderToken) {
|
||||
await this.onAppliquerJetEncaissement(jet, attackerToken);
|
||||
await this.$afficherEncaissement(jet, show, defenderToken);
|
||||
}
|
||||
|
||||
async onAppliquerJetEncaissement(encaissement, attackerToken) { }
|
||||
|
||||
async $afficherEncaissement(encaissement, show, defenderToken) {
|
||||
foundry.utils.mergeObject(encaissement, {
|
||||
alias: defenderToken?.name ?? this.getAlias(),
|
||||
hasPlayerOwner: this.hasPlayerOwner,
|
||||
show: show ?? {}
|
||||
}, { overwrite: false });
|
||||
|
||||
await ChatUtility.createChatWithRollMode(
|
||||
{
|
||||
roll: encaissement.roll,
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-encaissement.html', encaissement)
|
||||
},
|
||||
this
|
||||
)
|
||||
|
||||
if (!encaissement.hasPlayerOwner && encaissement.endurance != 0) {
|
||||
encaissement = foundry.utils.duplicate(encaissement)
|
||||
encaissement.isGM = true
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getGMs(),
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-encaissement.html', encaissement)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async accorder(entite, when = 'avant-encaissement') {
|
||||
if (when != game.settings.get(SYSTEM_RDD, "accorder-entite-cauchemar")
|
||||
|| entite == undefined
|
||||
|| !entite.isEntite([ENTITE_INCARNE])
|
||||
|| entite.isEntiteAccordee(this)) {
|
||||
return true;
|
||||
}
|
||||
const rolled = await RdDResolutionTable.roll(this.getReveActuel(), - Number(entite.getNiveau()));
|
||||
const rollData = {
|
||||
alias: this.getAlias(),
|
||||
rolled: rolled,
|
||||
entite: entite.name,
|
||||
selectedCarac: this.system.carac.reve
|
||||
};
|
||||
|
||||
if (rolled.isSuccess) {
|
||||
await entite.setEntiteReveAccordee(this);
|
||||
}
|
||||
|
||||
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-accorder-cauchemar.html');
|
||||
if (rolled.isPart) {
|
||||
await this.appliquerAjoutExperience(rollData, true);
|
||||
}
|
||||
return rolled.isSuccess;
|
||||
}
|
||||
|
||||
isEntiteAccordee(attacker) { return true }
|
||||
|
||||
async setEntiteReveAccordee(actor) {
|
||||
ui.notifications.error("Impossible de s'accorder à " + this.getAlias() + ": ce n'est pas une entité incarnée");
|
||||
}
|
||||
|
||||
}
|
46
module/actor/base-actor-sang-sheet.js
Normal file
@ -0,0 +1,46 @@
|
||||
import { ChatUtility } from "../chat-utility.js";
|
||||
import { RdDItemBlessure } from "../item/blessure.js";
|
||||
import { RdDBaseActorReveSheet } from "./base-actor-reve-sheet.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
* @extends {ActorSheet}
|
||||
*/
|
||||
export class RdDBaseActorSangSheet extends RdDBaseActorReveSheet {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
this.html.find('.creer-blessure-legere').click(async event => RdDItemBlessure.createBlessure(this.actor, 2));
|
||||
this.html.find('.creer-blessure-grave').click(async event => RdDItemBlessure.createBlessure(this.actor, 4));
|
||||
this.html.find('.creer-blessure-critique').click(async event => RdDItemBlessure.createBlessure(this.actor, 6));
|
||||
|
||||
this.html.find('.subir-blessure-contusion').click(async event => RdDItemBlessure.applyFullBlessure(this.actor, 0));
|
||||
this.html.find('.subir-blessure-legere').click(async event => RdDItemBlessure.applyFullBlessure(this.actor, 2));
|
||||
this.html.find('.subir-blessure-grave').click(async event => RdDItemBlessure.applyFullBlessure(this.actor, 4));
|
||||
this.html.find('.subir-blessure-critique').click(async event => RdDItemBlessure.applyFullBlessure(this.actor, 6));
|
||||
|
||||
this.html.find('.jet-vie').click(async event => this.actor.jetDeVie())
|
||||
this.html.find('.jet-endurance').click(async event => await this.jetEndurance())
|
||||
|
||||
this.html.find('.vie-plus').click(async event => this.actor.santeIncDec("vie", 1))
|
||||
this.html.find('.vie-moins').click(async event => this.actor.santeIncDec("vie", -1))
|
||||
}
|
||||
|
||||
async jetEndurance() {
|
||||
const endurance = this.actor.getEnduranceActuelle()
|
||||
const result = await this.actor.jetEndurance(endurance);
|
||||
ChatMessage.create({
|
||||
content: `Jet d'Endurance : ${result.jetEndurance} / ${endurance}
|
||||
<br>${this.actor.name} a ${result.sonne ? 'échoué' : 'réussi'} son Jet d'Endurance ${result.sonne ? 'et devient Sonné' : ''}`,
|
||||
whisper: ChatUtility.getOwners(this.actor)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
303
module/actor/base-actor-sang.js
Normal file
@ -0,0 +1,303 @@
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
|
||||
import { STATUSES } from "../settings/status-effects.js";
|
||||
import { ITEM_TYPES } from "../constants.js";
|
||||
import { RdDBaseActorReve } from "./base-actor-reve.js";
|
||||
import { RdDDice } from "../rdd-dice.js";
|
||||
import { RdDItemBlessure } from "../item/blessure.js";
|
||||
import { ChatUtility } from "../chat-utility.js";
|
||||
import { Misc } from "../misc.js";
|
||||
|
||||
/**
|
||||
* Classe de base pour les acteurs qui peuvent subir des blessures
|
||||
* - créatures
|
||||
* - humanoides
|
||||
*/
|
||||
export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
|
||||
prepareActorData() {
|
||||
this.system.sante.vie.max = Math.ceil((this.getTaille() + this.getConstitution()) / 2)
|
||||
this.system.sante.vie.value = Math.min(this.system.sante.vie.value, this.system.sante.vie.max)
|
||||
super.prepareActorData()
|
||||
this.system.attributs.encombrement.value = this.getEncombrementMax()
|
||||
}
|
||||
|
||||
getForce() { return Misc.toInt(this.system.carac.force?.value) }
|
||||
getConstitution() { return Misc.toInt(this.system.carac.constitution?.value) }
|
||||
getVolonte() { return Misc.toInt(this.system.carac.volonte?.value) }
|
||||
|
||||
getVieMax() { return Misc.toInt(this.system.sante.vie?.max) }
|
||||
getEnduranceMax() { return Math.max(1, this.getTaille() + this.getConstitution()) }
|
||||
getFatigueMax() { return this.getEnduranceMax() * 2 }
|
||||
|
||||
getProtectionNaturelle() { return Misc.toInt(this.system.attributs?.protection?.value) }
|
||||
|
||||
getFatigueActuelle() {
|
||||
if (ReglesOptionnelles.isUsing("appliquer-fatigue")) {
|
||||
return Math.max(0, Math.min(this.getFatigueMax(), Misc.toInt(this.system.sante.fatigue?.value)))
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
getFatigueRestante() { return this.getFatigueMax() - this.getFatigueActuelle() }
|
||||
getFatigueMin() { return this.system.sante.endurance.max - this.system.sante.endurance.value }
|
||||
|
||||
malusFatigue() {
|
||||
if (ReglesOptionnelles.isUsing("appliquer-fatigue")) {
|
||||
return RdDUtility.calculMalusFatigue(this.getFatigueActuelle(), this.getEnduranceMax())
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
isSurenc() { return this.computeMalusSurEncombrement() < 0 }
|
||||
|
||||
computeMalusSurEncombrement() {
|
||||
return Math.min(0, Math.floor(this.getEncombrementMax() - this.encTotal));
|
||||
}
|
||||
|
||||
isDead() { return this.system.sante.vie.value < -this.getSConst() }
|
||||
|
||||
nbBlessuresLegeres() { return this.itemTypes[ITEM_TYPES.blessure].filter(it => it.isLegere()).length }
|
||||
nbBlessuresGraves() { return this.itemTypes[ITEM_TYPES.blessure].filter(it => it.isGrave()).length }
|
||||
nbBlessuresCritiques() { return this.itemTypes[ITEM_TYPES.blessure].filter(it => it.isCritique()).length }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
computeResumeBlessure() {
|
||||
const nbLegeres = this.nbBlessuresLegeres()
|
||||
const nbGraves = this.nbBlessuresGraves()
|
||||
const nbCritiques = this.nbBlessuresCritiques()
|
||||
|
||||
if (nbLegeres + nbGraves + nbCritiques == 0) {
|
||||
return "Aucune blessure";
|
||||
}
|
||||
let resume = "Blessures:";
|
||||
if (nbLegeres > 0) {
|
||||
resume += " " + nbLegeres + " légère" + (nbLegeres > 1 ? "s" : "");
|
||||
}
|
||||
if (nbGraves > 0) {
|
||||
if (nbLegeres > 0)
|
||||
resume += ",";
|
||||
resume += " " + nbGraves + " grave" + (nbGraves > 1 ? "s" : "");
|
||||
}
|
||||
if (nbCritiques > 0) {
|
||||
if (nbGraves > 0 || nbLegeres > 0)
|
||||
resume += ",";
|
||||
resume += " une CRITIQUE !";
|
||||
}
|
||||
return resume;
|
||||
}
|
||||
|
||||
blessuresASoigner() { return [] }
|
||||
|
||||
async computeArmure(attackerRoll) { return this.getProtectionNaturelle() }
|
||||
async remiseANeuf() { }
|
||||
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
async onAppliquerJetEncaissement(encaissement, attackerToken) {
|
||||
const santeOrig = foundry.utils.duplicate(this.system.sante);
|
||||
const blessure = await this.ajouterBlessure(encaissement, attackerToken); // Will update the result table
|
||||
const perteVie = await this.santeIncDec("vie", -encaissement.vie);
|
||||
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance, blessure?.isCritique());
|
||||
|
||||
foundry.utils.mergeObject(encaissement, {
|
||||
resteEndurance: perteEndurance.newValue,
|
||||
sonne: perteEndurance.sonne,
|
||||
jetEndurance: perteEndurance.jetEndurance,
|
||||
endurance: perteEndurance.perte,
|
||||
vie: santeOrig.vie.value - perteVie.newValue,
|
||||
blessure: blessure
|
||||
});
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async santeIncDec(name, inc, isCritique = false) {
|
||||
if (name == 'fatigue' && !ReglesOptionnelles.isUsing("appliquer-fatigue")) {
|
||||
return;
|
||||
}
|
||||
const sante = foundry.utils.duplicate(this.system.sante)
|
||||
let compteur = sante[name];
|
||||
if (!compteur) {
|
||||
return;
|
||||
}
|
||||
let result = {
|
||||
sonne: false,
|
||||
};
|
||||
|
||||
let minValue = name == "vie" ? -this.getSConst() - 1 : 0;
|
||||
|
||||
result.newValue = Math.max(minValue, Math.min(compteur.value + inc, compteur.max));
|
||||
//console.log("New value ", inc, minValue, result.newValue);
|
||||
let fatigue = 0;
|
||||
if (name == "endurance") {
|
||||
if (result.newValue == 0 && inc < 0 && !isCritique) { // perte endurance et endurance devient 0 (sauf critique) -> -1 vie
|
||||
sante.vie.value--;
|
||||
result.perteVie = true;
|
||||
}
|
||||
result.newValue = Math.max(0, result.newValue);
|
||||
if (inc > 0) { // le max d'endurance s'applique seulement à la récupération
|
||||
result.newValue = Math.min(result.newValue, this._computeEnduranceMax())
|
||||
}
|
||||
const perte = compteur.value - result.newValue;
|
||||
result.perte = perte;
|
||||
if (perte > 1) {
|
||||
// Peut-être sonné si 2 points d'endurance perdus d'un coup
|
||||
foundry.utils.mergeObject(result, await this.jetEndurance(result.newValue));
|
||||
} else if (inc > 0) {
|
||||
await this.setSonne(false);
|
||||
}
|
||||
if (sante.fatigue && inc < 0) { // Each endurance lost -> fatigue lost
|
||||
fatigue = perte;
|
||||
}
|
||||
}
|
||||
compteur.value = result.newValue;
|
||||
// If endurance lost, then the same amount of fatigue cannot be recovered
|
||||
if (ReglesOptionnelles.isUsing("appliquer-fatigue") && sante.fatigue && fatigue > 0) {
|
||||
sante.fatigue.value = Math.max(sante.fatigue.value + fatigue, this.getFatigueMin());
|
||||
}
|
||||
await this.update({ "system.sante": sante })
|
||||
if (this.isDead()) {
|
||||
await this.setEffect(STATUSES.StatusComma, true);
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_computeEnduranceMax() {
|
||||
const diffVie = this.system.sante.vie.max - this.system.sante.vie.value;
|
||||
const maxEndVie = this.system.sante.endurance.max - (diffVie * 2);
|
||||
const nbGraves = this.countBlessures(it => it.isGrave()) > 0
|
||||
const nbCritiques = this.countBlessures(it => it.isCritique()) > 0
|
||||
const maxEndGraves = Math.floor(this.system.sante.endurance.max / (2 * nbGraves));
|
||||
const maxEndCritiques = nbCritiques > 0 ? 1 : this.system.sante.endurance.max;
|
||||
return Math.max(0, Math.min(maxEndVie, maxEndGraves, maxEndCritiques));
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async ajouterBlessure(encaissement, attackerToken = undefined) {
|
||||
if (encaissement.gravite < 0) return;
|
||||
if (encaissement.gravite > 0) {
|
||||
while (this.countBlessures(it => it.system.gravite == encaissement.gravite) >= RdDItemBlessure.maxBlessures(encaissement.gravite) && encaissement.gravite <= 6) {
|
||||
// Aggravation
|
||||
encaissement.gravite += 2
|
||||
if (encaissement.gravite > 2) {
|
||||
encaissement.vie += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
const endActuelle = this.getEnduranceActuelle();
|
||||
const blessure = await RdDItemBlessure.createBlessure(this, encaissement.gravite, encaissement.dmg?.loc.label ?? '', attackerToken);
|
||||
if (blessure.isCritique()) {
|
||||
encaissement.endurance = endActuelle;
|
||||
}
|
||||
|
||||
if (blessure.isMort()) {
|
||||
this.setEffect(STATUSES.StatusComma, true);
|
||||
encaissement.mort = true;
|
||||
ChatMessage.create({
|
||||
content: `<img class="chat-icon" src="icons/svg/skull.svg" data-tooltip="charge" />
|
||||
<strong>${this.getAlias()} vient de succomber à une seconde blessure critique ! Que les Dragons gardent son Archétype en paix !</strong>`
|
||||
});
|
||||
}
|
||||
return blessure;
|
||||
}
|
||||
|
||||
async supprimerBlessure({ gravite }) {
|
||||
const toDelete = this.itemTypes[ITEM_TYPES.blessure].find(it => it.system.gravite == gravite)?.id
|
||||
if (toDelete) {
|
||||
await this.deleteEmbeddedDocuments('Item', [toDelete]);
|
||||
}
|
||||
}
|
||||
|
||||
async supprimerBlessures(filterToDelete) {
|
||||
const toDelete = this.filterItems(filterToDelete, ITEM_TYPES.blessure)
|
||||
.map(it => it.id);
|
||||
await this.deleteEmbeddedDocuments('Item', toDelete);
|
||||
}
|
||||
|
||||
countBlessures(filter = it => !it.isContusion()) {
|
||||
return this.filterItems(filter, ITEM_TYPES.blessure).length
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async jetDeVie() {
|
||||
if (this.isDead()) {
|
||||
ChatMessage.create({
|
||||
content: `Jet de Vie: ${this.getAlias()} est déjà mort, ce n'est pas la peine d'en rajouter !!!!!`,
|
||||
whisper: ChatUtility.getOwners(this)
|
||||
})
|
||||
return
|
||||
}
|
||||
const jetDeVie = await RdDDice.roll("1d20");
|
||||
|
||||
const sConst = this.getSConst();
|
||||
const vie = this.system.sante.vie.value;
|
||||
const isCritique = this.nbBlessuresCritiques() > 0;
|
||||
const isGrave = this.nbBlessuresGraves();
|
||||
const isEchecTotal = jetDeVie.total == 20;
|
||||
const isSuccess = jetDeVie.total == 1 || jetDeVie.total <= vie;
|
||||
const perte = isSuccess ? 0 : 1 + (isEchecTotal ? vie + sConst : 0)
|
||||
const prochainJet = (jetDeVie.total == 1 && vie > 0 ? 20 : 1) * (isCritique ? 1 : isGrave > 0 ? sConst : 0)
|
||||
|
||||
let msgText = `Jet de Vie: <strong>${jetDeVie.total} / ${vie}</strong>`
|
||||
if (isSuccess) {
|
||||
msgText += "<br>Réussi, pas de perte de point de vie."
|
||||
} else {
|
||||
msgText += `<br>Echoué, perte ${perte} point de vie`;
|
||||
await this.santeIncDec("vie", -perte);
|
||||
}
|
||||
if (this.isDead()) {
|
||||
msgText += `<br><strong>${this.getAlias()} est mort !!!!</strong>`;
|
||||
}
|
||||
else if (prochainJet > 0) {
|
||||
msgText += `<br>Prochain jet de vie dans ${prochainJet} ${isCritique ? 'round' : 'minute'}${prochainJet > 1 ? 's' : ''} ${isCritique ? '(état critique)' : '(état grave)'}`
|
||||
}
|
||||
ChatMessage.create({
|
||||
content: msgText,
|
||||
whisper: ChatUtility.getOwners(this)
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async jetEndurance(resteEndurance = undefined) {
|
||||
const jetEndurance = (await RdDDice.roll("1d20")).total;
|
||||
const sonne = jetEndurance == 20 || jetEndurance > (resteEndurance ?? this.system.sante.endurance.value)
|
||||
if (sonne) {
|
||||
await this.setSonne();
|
||||
}
|
||||
return { jetEndurance, sonne }
|
||||
}
|
||||
|
||||
async finDeRoundBlessures() {
|
||||
const nbGraves = this.filterItems(it => it.isGrave(), 'blessure').length;
|
||||
if (nbGraves > 0) {
|
||||
// Gestion blessure graves : -1 pt endurance par blessure grave
|
||||
await this.santeIncDec("endurance", -nbGraves);
|
||||
}
|
||||
}
|
||||
|
||||
async setSonne(sonne = true) {
|
||||
if (!game.combat && sonne) {
|
||||
ui.notifications.info(`${this.getAlias()} est hors combat, il ne reste donc pas sonné`);
|
||||
return;
|
||||
}
|
||||
await this.setEffect(STATUSES.StatusStunned, sonne)
|
||||
}
|
||||
|
||||
isSonne() {
|
||||
return this.getEffect(STATUSES.StatusStunned)
|
||||
}
|
||||
|
||||
isEffectAllowed(effectId) { return true }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async computeEtatGeneral() { this.system.compteurs.etat.value = this.malusVie() + this.malusFatigue() + this.malusEthylisme() }
|
||||
getEtatGeneral(options = { ethylisme: false }) { return this.system.compteurs.etat.value }
|
||||
|
||||
malusVie() { return Math.min(this.system.sante.vie.value - this.system.sante.vie.max, 0) }
|
||||
malusEthylisme() { return 0 }
|
||||
|
||||
|
||||
}
|
@ -3,7 +3,11 @@ import { Misc } from "../misc.js";
|
||||
import { DialogSplitItem } from "../dialog-split-item.js";
|
||||
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
|
||||
import { Monnaie } from "../item-monnaie.js";
|
||||
import { ITEM_TYPES } from "../constants.js";
|
||||
import { RdDItem } from "../item.js";
|
||||
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
|
||||
import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js";
|
||||
import { ItemAction } from "../item/item-actions.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/**
|
||||
@ -14,23 +18,19 @@ export class RdDBaseActorSheet extends ActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
RdDUtility.initAfficheContenu();
|
||||
return mergeObject(super.defaultOptions, {
|
||||
return foundry.utils.mergeObject(ActorSheet.defaultOptions, {
|
||||
classes: ["rdd", "sheet", "actor"],
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html",
|
||||
width: 550,
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }],
|
||||
showCompNiveauBase: false,
|
||||
vueDetaillee: false
|
||||
});
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
Monnaie.validerMonnaies(this.actor.itemTypes['monnaie']);
|
||||
Monnaie.validerMonnaies(this.actor)
|
||||
|
||||
this.actor.recompute();
|
||||
this.actor.computeEtatGeneral();
|
||||
let formData = {
|
||||
title: this.title,
|
||||
id: this.actor.id,
|
||||
@ -38,28 +38,32 @@ export class RdDBaseActorSheet extends ActorSheet {
|
||||
img: this.actor.img,
|
||||
name: this.actor.name,
|
||||
system: this.actor.system,
|
||||
description: await TextEditor.enrichHTML(this.actor.system.description, { async: true }),
|
||||
notesmj: await TextEditor.enrichHTML(this.actor.system.notesmj, { async: true }),
|
||||
options: RdDSheetUtility.mergeDocumentRights(this.options, this.actor, this.isEditable)
|
||||
description: await RdDTextEditor.enrichHTML(this.actor.system.description, this.actor),
|
||||
notesmj: await RdDTextEditor.enrichHTML(this.actor.system.notesmj, this.actor),
|
||||
options: RdDSheetUtility.mergeDocumentRights(this.options, this.actor, this.isEditable),
|
||||
effects: this.actor.effects
|
||||
}
|
||||
|
||||
RdDBaseActorSheet.filterItemsPerTypeForSheet(formData, this.actor.itemTypes);
|
||||
RdDUtility.filterItemsPerTypeForSheet(formData, this.actor.itemTypes);
|
||||
formData.calc = {
|
||||
fortune: Monnaie.toSolsDeniers(this.actor.getFortune()),
|
||||
prixTotalEquipement: this.actor.computePrixTotalEquipement(),
|
||||
encTotal: await this.actor.computeEncTotal(),
|
||||
}
|
||||
|
||||
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
|
||||
this._appliquerRechercheObjets(formData.objets, formData.conteneurs);
|
||||
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.inventaires);
|
||||
this._appliquerRechercheObjets(formData.conteneurs, formData.inventaires);
|
||||
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
|
||||
formData.competences.filter(it => it.type == ITEM_TYPES.competencecreature)
|
||||
.forEach(it => it.isdommages = RdDItemCompetenceCreature.isDommages(it))
|
||||
|
||||
return formData;
|
||||
}
|
||||
|
||||
_appliquerRechercheObjets(objets, conteneurs) {
|
||||
_appliquerRechercheObjets(conteneurs, inventaires) {
|
||||
if (this.options.recherche?.text) {
|
||||
const recherche = this.options.recherche;
|
||||
const allVisible = objets.filter(it => it.isNomTypeLike(recherche.text)).map(it => it.id);
|
||||
const allVisible = inventaires.filter(it => it.isNomTypeLike(recherche.text)).map(it => it.id);
|
||||
let addVisible = conteneurs.filter(it => it.isNomTypeLike(recherche.text)).map(it => it.id)
|
||||
do {
|
||||
allVisible.push(...addVisible)
|
||||
@ -67,95 +71,45 @@ export class RdDBaseActorSheet extends ActorSheet {
|
||||
addVisible = parentsIds.filter(id => !allVisible.includes(id))
|
||||
}
|
||||
while (addVisible.length > 0)
|
||||
objets.forEach(it => it.system.isHidden = !allVisible.includes(it.id))
|
||||
inventaires.forEach(it => it.system.isHidden = !allVisible.includes(it.id))
|
||||
conteneurs.forEach(it => it.system.isHidden = !allVisible.includes(it.id))
|
||||
}
|
||||
else {
|
||||
objets.forEach(it => it.system.isHidden = false)
|
||||
inventaires.forEach(it => it.system.isHidden = false)
|
||||
conteneurs.forEach(it => it.system.isHidden = false)
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static filterItemsPerTypeForSheet(formData, itemTypes) {
|
||||
formData.blessures = Misc.arrayOrEmpty(itemTypes['blessure']);
|
||||
formData.recettescuisine = Misc.arrayOrEmpty(itemTypes['recettecuisine']);
|
||||
formData.recettesAlchimiques = Misc.arrayOrEmpty(itemTypes['recettealchimique']);
|
||||
formData.maladies = Misc.arrayOrEmpty(itemTypes['maladie']);
|
||||
formData.poisons = Misc.arrayOrEmpty(itemTypes['poison']);
|
||||
formData.possessions = Misc.arrayOrEmpty(itemTypes['possession']);
|
||||
formData.maladiesPoisons = formData.maladies.concat(formData.poisons);
|
||||
formData.competences = (itemTypes['competence'] ?? []).concat(itemTypes['competencecreature'] ?? []);
|
||||
formData.sortsReserve = Misc.arrayOrEmpty(itemTypes['sortreserve']);
|
||||
/* -------------------------------------------- */ /** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
|
||||
formData.sorts = Misc.arrayOrEmpty(itemTypes['sort']);
|
||||
formData.rencontres = Misc.arrayOrEmpty(itemTypes['rencontre']);
|
||||
formData.casestmr = Misc.arrayOrEmpty(itemTypes['casetmr']);
|
||||
formData.signesdraconiques = Misc.arrayOrEmpty(itemTypes['signedraconique']);
|
||||
formData.queues = Misc.arrayOrEmpty(itemTypes['queue']);
|
||||
formData.souffles = Misc.arrayOrEmpty(itemTypes['souffle']);
|
||||
formData.ombres = Misc.arrayOrEmpty(itemTypes['ombre']);
|
||||
formData.tetes = Misc.arrayOrEmpty(itemTypes['tete']);
|
||||
formData.taches = Misc.arrayOrEmpty(itemTypes['tache']);
|
||||
formData.meditations = Misc.arrayOrEmpty(itemTypes['meditation']);
|
||||
formData.chants = Misc.arrayOrEmpty(itemTypes['chant']);
|
||||
formData.danses = Misc.arrayOrEmpty(itemTypes['danse']);
|
||||
formData.musiques = Misc.arrayOrEmpty(itemTypes['musique']);
|
||||
formData.oeuvres = Misc.arrayOrEmpty(itemTypes['oeuvre']);
|
||||
formData.jeux = Misc.arrayOrEmpty(itemTypes['jeu']);
|
||||
this.html.find('.actionItem').click(event => ItemAction.onActionItem(event, this.actor, this.options))
|
||||
this.html.find('.item-edit').click(async event => this.itemActionEdit(event))
|
||||
this.html.find('.conteneur-name a').click(async event => {
|
||||
RdDUtility.toggleAfficheContenu(this.getItemId(event))
|
||||
this.render(true)
|
||||
})
|
||||
|
||||
formData.services = Misc.arrayOrEmpty(itemTypes['service']);
|
||||
formData.conteneurs = Misc.arrayOrEmpty(itemTypes['conteneur']);
|
||||
formData.materiel = Misc.arrayOrEmpty(itemTypes['objet']);
|
||||
formData.armes = Misc.arrayOrEmpty(itemTypes['arme']);
|
||||
formData.armures = Misc.arrayOrEmpty(itemTypes['armure']);
|
||||
formData.munitions = Misc.arrayOrEmpty(itemTypes['munition']);
|
||||
formData.livres = Misc.arrayOrEmpty(itemTypes['livre']);
|
||||
formData.potions = Misc.arrayOrEmpty(itemTypes['potion']);
|
||||
formData.plantes = Misc.arrayOrEmpty(itemTypes['plante']);
|
||||
formData.ingredients = Misc.arrayOrEmpty(itemTypes['ingredient']);
|
||||
formData.faunes = Misc.arrayOrEmpty(itemTypes['faune']);
|
||||
formData.herbes = Misc.arrayOrEmpty(itemTypes['herbe']);
|
||||
formData.nourritureboissons = Misc.arrayOrEmpty(itemTypes['nourritureboisson']);
|
||||
formData.gemmes = Misc.arrayOrEmpty(itemTypes['gemme']);
|
||||
formData.monnaie = Misc.arrayOrEmpty(itemTypes['monnaie']).sort(Monnaie.triValeurEntiere());
|
||||
this.html.find('.actor-montrer').click(async event => this.actor.postActorToChat());
|
||||
|
||||
this.html.find('.recherche')
|
||||
.each((index, field) => {
|
||||
this._rechercheSelectArea(field);
|
||||
})
|
||||
.keyup(async event => this._rechercherKeyup(event))
|
||||
.change(async event => this._rechercherKeyup(event))
|
||||
|
||||
this.html.find('.recherche').prop("disabled", false)
|
||||
|
||||
formData.objets = RdDItem.getItemTypesInventaire('all')
|
||||
.map(t => Misc.arrayOrEmpty(itemTypes[t]))
|
||||
.reduce((a, b) => a.concat(b), [])
|
||||
.sort(Misc.ascending(it => it.name));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */ /** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
|
||||
this.html.find('.conteneur-name a').click(async event => {
|
||||
RdDUtility.toggleAfficheContenu(this.getItemId(event));
|
||||
this.render(true);
|
||||
});
|
||||
this.html.find('.item-edit').click(async event => this.getItem(event)?.sheet.render(true))
|
||||
this.html.find('.item-montrer').click(async event => this.getItem(event)?.postItemToChat());
|
||||
this.html.find('.actor-montrer').click(async event => this.actor.postActorToChat());
|
||||
this.html.find('.recherche')
|
||||
.each((index, field) => {
|
||||
this._rechercheSelectArea(field);
|
||||
})
|
||||
.keyup(async event => this._rechercherKeyup(event))
|
||||
.change(async event => this._rechercherKeyup(event));
|
||||
this.html.find('.recherche').prop( "disabled", false );
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
this.html.find('.item-split').click(async event => {
|
||||
const item = this.getItem(event);
|
||||
RdDSheetUtility.splitItem(item, this.actor);
|
||||
});
|
||||
this.html.find('.item-equip-armure').click(async event => this.actor.equiperObjet(this.getItem(event)))
|
||||
this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this.getItem(event), this.actor));
|
||||
this.html.find('.item-quantite-plus').click(async event => this.actor.itemQuantiteIncDec(this.getItemId(event), 1));
|
||||
this.html.find('.item-quantite-moins').click(async event => this.actor.itemQuantiteIncDec(this.getItemId(event), -1));
|
||||
this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, this.getItem(event)));
|
||||
this.html.find('.item-vendre').click(async event => this.vendre(this.getItem(event)));
|
||||
|
||||
this.html.find('.creer-un-objet').click(async event => {
|
||||
this.selectObjetTypeToCreate();
|
||||
@ -163,6 +117,16 @@ export class RdDBaseActorSheet extends ActorSheet {
|
||||
this.html.find('.nettoyer-conteneurs').click(async event => {
|
||||
this.actor.nettoyerConteneurs();
|
||||
});
|
||||
|
||||
this.html.find('.vue-detaillee').click(async event => {
|
||||
this.options.vueDetaillee = !this.options.vueDetaillee;
|
||||
this.render(true);
|
||||
});
|
||||
}
|
||||
|
||||
itemActionEdit(event) {
|
||||
const item = this.getItem(event);
|
||||
return item?.sheet.render(true);
|
||||
}
|
||||
|
||||
_rechercherKeyup(event) {
|
||||
@ -230,9 +194,9 @@ export class RdDBaseActorSheet extends ActorSheet {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async selectObjetTypeToCreate() {
|
||||
let typeObjets = this.getTypesInventaire().sort(Misc.ascending(type => Misc.typeName('Item', type)));
|
||||
let content = `<span class="competence-label">Selectionnez le type d'équipement</span><select class="item-type">`;
|
||||
for (let typeName of typeObjets) {
|
||||
let types = this.getTypesInventaire().sort(Misc.ascending(type => Misc.typeName('Item', type)));
|
||||
let content = `<span class="generic-label">Selectionnez le type d'équipement</span><select class="item-type">`;
|
||||
for (let typeName of types) {
|
||||
content += `<option value="${typeName}">${Misc.typeName('Item', typeName)}</option>`
|
||||
}
|
||||
content += '</select>';
|
||||
@ -284,7 +248,7 @@ export class RdDBaseActorSheet extends ActorSheet {
|
||||
async _onSplitItem(item, split) {
|
||||
if (split >= 1 && split < item.system.quantite) {
|
||||
await item.diminuerQuantite(split);
|
||||
const splitItem = duplicate(item);
|
||||
const splitItem = foundry.utils.duplicate(item);
|
||||
splitItem.system.quantite = split;
|
||||
await this.actor.createEmbeddedDocuments('Item', [splitItem])
|
||||
}
|
||||
|
@ -1,74 +1,114 @@
|
||||
import { ChatVente } from "../achat-vente/chat-vente.js";
|
||||
import { ChatUtility } from "../chat-utility.js";
|
||||
import { SYSTEM_SOCKET_ID } from "../constants.js";
|
||||
import { Grammar } from "../grammar.js";
|
||||
import { Monnaie } from "../item-monnaie.js";
|
||||
import { ITEM_TYPES } from "../constants.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { RdDAudio } from "../rdd-audio.js";
|
||||
import { RdDConfirm } from "../rdd-confirm.js";
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
import { SystemCompendiums } from "../settings/system-compendiums.js";
|
||||
import { APP_ASTROLOGIE_REFRESH } from "../sommeil/app-astrologie.js";
|
||||
|
||||
export class RdDBaseActor extends Actor {
|
||||
|
||||
static _findCaracNode(carac, name) {
|
||||
return Object.entries(carac)
|
||||
.filter(it => Grammar.equalsInsensitive(it[1].label, name))
|
||||
.map(it => it[0])
|
||||
.find(it => it)
|
||||
}
|
||||
|
||||
static $findCaracByName(carac, name) {
|
||||
const caracList = Object.entries(carac);
|
||||
let entry = Misc.findFirstLike(name, caracList, { mapper: it => it[0], description: 'caractéristique', onMessage: m => { } });
|
||||
if (!entry || entry.length == 0) {
|
||||
entry = Misc.findFirstLike(name, caracList, { mapper: it => it[1].label, description: 'caractéristique' });
|
||||
}
|
||||
return entry && entry.length > 0 ? carac[entry[0]] : undefined;
|
||||
}
|
||||
static getDefaultValue(actorType, path) {
|
||||
if (path.includes('.')) {
|
||||
path = path.split('.')
|
||||
}
|
||||
let obj = game.model.Actor[actorType]
|
||||
for (let p of path) {
|
||||
obj = obj ? obj[p] : undefined
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
static getDefaultImg(itemType) {
|
||||
return game.system.rdd.actorClasses[itemType]?.defaultIcon ?? defaultItemImg[itemType];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static init() {
|
||||
Hooks.on("preUpdateItem", (item, change, options, id) => RdDBaseActor.getParentActor(item)?.onPreUpdateItem(item, change, options, id));
|
||||
Hooks.on("createItem", (item, options, id) => RdDBaseActor.getParentActor(item)?.onCreateItem(item, options, id));
|
||||
Hooks.on("deleteItem", (item, options, id) => RdDBaseActor.getParentActor(item)?.onDeleteItem(item, options, id));
|
||||
Hooks.on("updateActor", (actor, change, options, actorId) => actor.onUpdateActor(change, options, actorId));
|
||||
Hooks.on("preUpdateItem", (item, change, options, id) => Misc.documentIfResponsible(item.parent)?.onPreUpdateItem(item, change, options, id))
|
||||
Hooks.on("createItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onCreateItem(item, options, id))
|
||||
Hooks.on("deleteItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onDeleteItem(item, options, id))
|
||||
Hooks.on("updateActor", (actor, change, options, actorId) => Misc.documentIfResponsible(actor)?.onUpdateActor(change, options, actorId))
|
||||
}
|
||||
|
||||
static onSocketMessage(sockmsg) {
|
||||
switch (sockmsg.msg) {
|
||||
case "msg_remote_actor_call":
|
||||
return RdDBaseActor.onRemoteActorCall(sockmsg.data, sockmsg.userId);
|
||||
case "msg_reset_nombre_astral":
|
||||
game.user.character.resetNombresAstraux();
|
||||
game.system.rdd.calendrier.notifyChangeNombresAstraux();
|
||||
return;
|
||||
case "msg_refresh_nombre_astral":
|
||||
Hooks.callAll(APP_ASTROLOGIE_REFRESH);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static remoteActorCall(callData, userId = undefined) {
|
||||
userId = userId ?? Misc.firstConnectedGMId();
|
||||
if (userId == game.user.id) {
|
||||
RdDBaseActor.onRemoteActorCall(callData, userId);
|
||||
return false;
|
||||
static remoteActorCall(callData) {
|
||||
if (game.user.isGM) {
|
||||
RdDBaseActor.onRemoteActorCall(callData, game.user.id)
|
||||
return false
|
||||
}
|
||||
else {
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_remote_actor_call", data: callData, userId: userId });
|
||||
return true;
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, {
|
||||
msg: "msg_remote_actor_call",
|
||||
data: callData,
|
||||
userId: Misc.firstConnectedGMId()
|
||||
})
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
static onRemoteActorCall(callData, userId) {
|
||||
const actor = RdDBaseActor.getRealActor(callData?.actorId, callData?.tokenId);
|
||||
if (userId == game.user.id) {
|
||||
const actor = game.actors.get(callData?.actorId);
|
||||
if (Misc.isOwnerPlayerOrUniqueConnectedGM(actor)) { // Seul le joueur choisi effectue l'appel: le joueur courant si propriétaire de l'actor, ou le MJ sinon
|
||||
const args = callData.args;
|
||||
console.info(`RdDBaseActor.onRemoteActorCall: pour l'Actor ${callData.actorId}, appel de RdDBaseActor.${callData.method}(`, ...args, ')');
|
||||
actor[callData.method](...args);
|
||||
}
|
||||
// Seul le joueur choisi effectue l'appel: le joueur courant si propriétaire de l'actor, ou le MJ sinon
|
||||
const args = callData.args;
|
||||
console.info(`RdDBaseActor.onRemoteActorCall: pour l'Actor ${callData.actorId}, appel de RdDBaseActor.${callData.method}(`, ...args, ')');
|
||||
actor[callData.method](...args);
|
||||
}
|
||||
}
|
||||
|
||||
static getParentActor(document) {
|
||||
return document?.parent instanceof Actor ? document.parent : undefined
|
||||
static getRealActor(actorId, tokenId) {
|
||||
if (tokenId) {
|
||||
let token = canvas.tokens.get(tokenId)
|
||||
if (token) {
|
||||
return token.actor
|
||||
}
|
||||
}
|
||||
return game.actors.get(actorId)
|
||||
}
|
||||
|
||||
getAlias() {
|
||||
if (this.token?.name != null && this.token != this.prototypeToken) {
|
||||
return this.token.name
|
||||
}
|
||||
return this.name
|
||||
}
|
||||
|
||||
isPersonnageJoueur() { return false }
|
||||
|
||||
static extractActorMin = (actor) => { return { id: actor?.id, type: actor?.type, name: actor?.name, img: actor?.img }; };
|
||||
|
||||
/**
|
||||
* Cet methode surcharge Actor.create() pour ajouter si besoin des Items par défaut:
|
||||
* Cette methode surcharge Actor.create() pour ajouter si besoin des Items par défaut:
|
||||
* compétences et monnaies.
|
||||
*
|
||||
* @param {Object} actorData template d'acteur auquel ajouter des informations.
|
||||
* @param {Object} options optionspour customiser la création
|
||||
*/
|
||||
*
|
||||
* @param {Object} actorData template d'acteur auquel ajouter des informations.
|
||||
* @param {Object} options optionspour customiser la création
|
||||
*/
|
||||
static async create(actorData, options) {
|
||||
// import depuis un compendium
|
||||
if (actorData instanceof Array) {
|
||||
@ -92,7 +132,7 @@ export class RdDBaseActor extends Actor {
|
||||
|
||||
constructor(docData, context = {}) {
|
||||
if (!context.rdd?.ready) {
|
||||
mergeObject(context, { rdd: { ready: true } });
|
||||
foundry.utils.mergeObject(context, { rdd: { ready: true } });
|
||||
const ActorConstructor = game.system.rdd.actorClasses[docData.type];
|
||||
if (ActorConstructor) {
|
||||
if (!docData.img) {
|
||||
@ -101,14 +141,80 @@ export class RdDBaseActor extends Actor {
|
||||
return new ActorConstructor(docData, context);
|
||||
}
|
||||
}
|
||||
context.rdd = undefined
|
||||
super(docData, context);
|
||||
}
|
||||
|
||||
isCreatureEntite() { return this.type == 'creature' || this.type == 'entite'; }
|
||||
isCreature() { return this.type == 'creature'; }
|
||||
isEntite() { return this.type == 'entite'; }
|
||||
isPersonnage() { return this.type == 'personnage'; }
|
||||
isVehicule() { return this.type == 'vehicule'; }
|
||||
findCaracByName(name) {
|
||||
name = Grammar.toLowerCaseNoAccent(name)
|
||||
switch (name) {
|
||||
case 'reve-actuel': case 'reve actuel':
|
||||
return this.system.carac.reve
|
||||
case 'chance-actuelle': case 'chance actuelle':
|
||||
return this.system.carac.chance
|
||||
case 'vie':
|
||||
return this.system.sante.vie
|
||||
}
|
||||
|
||||
const carac = this.system.carac;
|
||||
return RdDBaseActor.$findCaracByName(carac, name);
|
||||
}
|
||||
|
||||
mapCarac(caracCode) { return caracCode }
|
||||
|
||||
getCaracByName(name) {
|
||||
name = this.mapCarac(Grammar.toLowerCaseNoAccent(name))
|
||||
switch (name) {
|
||||
case 'reve-actuel': case 'reve actuel':
|
||||
return this.getCaracReveActuel();
|
||||
case 'chance-actuelle': case 'chance-actuelle':
|
||||
return this.getCaracChanceActuelle();
|
||||
}
|
||||
return this.findCaracByName(name);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _preCreate(data, options, user) {
|
||||
await super._preCreate(data, options, user);
|
||||
|
||||
// Configure prototype token settings
|
||||
if (this.type === "personnage") {
|
||||
this.updateSource({
|
||||
sight: { enabled: true },
|
||||
actorLink: options.fromCompendium ? data.prototypeToken.actorLink : true,
|
||||
disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY
|
||||
})
|
||||
} else {
|
||||
const prototypeToken = {
|
||||
sight: { enabled: true },
|
||||
disposition: CONST.TOKEN_DISPOSITIONS.NEUTRAL
|
||||
}
|
||||
this.updateSource({ prototypeToken });
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
prepareData() {
|
||||
super.prepareData()
|
||||
this.prepareActorData()
|
||||
this.cleanupConteneurs()
|
||||
this.computeEtatGeneral()
|
||||
this.computeEncTotal()
|
||||
}
|
||||
|
||||
prepareActorData() { }
|
||||
|
||||
async computeEtatGeneral() { }
|
||||
/* -------------------------------------------- */
|
||||
findPlayer() {
|
||||
return game.users.players.find(player => player.active && player.character?.id == this.id);
|
||||
}
|
||||
|
||||
isCreatureEntite() { return this.isCreature() || this.isEntite() }
|
||||
isCreature() { return false }
|
||||
isEntite(typeentite = []) { return false }
|
||||
isVehicule() { return false }
|
||||
isPersonnage() { return false }
|
||||
getItem(id, type = undefined) {
|
||||
const item = this.items.get(id);
|
||||
if (type == undefined || (item?.type == type)) {
|
||||
@ -117,32 +223,68 @@ export class RdDBaseActor extends Actor {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
listeSuivants(filter = suivant => true) { return [] }
|
||||
listeSuivants(filter = suivant => true) { return [] }
|
||||
listItems(type = undefined) { return (type ? this.itemTypes[type] : this.items); }
|
||||
filterItems(filter, type = undefined) { return type ? this.itemTypes[type]?.filter(filter) ?? [] : []; }
|
||||
filterItems(filter, type = undefined) { return (type ? this.itemTypes[type] : this.items)?.filter(filter) ?? []; }
|
||||
findItemLike(idOrName, type) {
|
||||
return this.getItem(idOrName, type)
|
||||
?? Misc.findFirstLike(idOrName, this.listItems(type), { description: Misc.typeName('Item', type) });
|
||||
}
|
||||
|
||||
getMonnaie(id) { return this.findItemLike(id, 'monnaie'); }
|
||||
|
||||
recompute() { }
|
||||
|
||||
getEncombrementMax() { return 0 }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async updateCarac(caracName, to) {
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async onPreUpdateItem(item, change, options, id) { }
|
||||
|
||||
async onCreateItem(item, options, id) { }
|
||||
|
||||
async onDeleteItem(item, options, id) { }
|
||||
|
||||
async onUpdateActor(update, options, actorId) { }
|
||||
async onDeleteItem(item, options, id) {
|
||||
if (item.isInventaire()) {
|
||||
this._removeItemFromConteneur(item)
|
||||
}
|
||||
}
|
||||
|
||||
_removeItemFromConteneur(item) {
|
||||
this.items.filter(it => it.isConteneur() && it.system.contenu.includes(item.id))
|
||||
.forEach(conteneur => {
|
||||
const nouveauContenu = conteneur.system.contenu.filter(id => id != item.id);
|
||||
conteneur.update({ 'system.contenu': nouveauContenu });
|
||||
});
|
||||
}
|
||||
|
||||
async onTimeChanging(oldTimestamp, newTimestamp) {
|
||||
this.items.filter(it => it.isFinPeriode(oldTimestamp, newTimestamp))
|
||||
.forEach(async it => await it.onFinPeriodeTemporel(oldTimestamp, newTimestamp))
|
||||
}
|
||||
|
||||
async creerObjetParMJ(object) {
|
||||
if (this.isOwner) {
|
||||
await this.createEmbeddedDocuments('Item', [object])
|
||||
return
|
||||
}
|
||||
RdDBaseActor.remoteActorCall({
|
||||
tokenId: this.token?.id,
|
||||
actorId: this.id,
|
||||
method: 'creerObjetParMJ', args: [object]
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async cleanupConteneurs() {
|
||||
if (Misc.isOwnerPlayer(this)) {
|
||||
let updates = this.itemTypes['conteneur']
|
||||
.filter(c => c.system.contenu.filter(id => this.getItem(id) == undefined).length > 0)
|
||||
.map(c => { return { _id: c._id, 'system.contenu': c.system.contenu.filter(id => this.getItem(id) != undefined) } });
|
||||
if (updates.length > 0) {
|
||||
await this.updateEmbeddedDocuments("Item", updates)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getFortune() {
|
||||
return Monnaie.getFortune(this.itemTypes['monnaie']);
|
||||
@ -153,7 +295,7 @@ export class RdDBaseActor extends Actor {
|
||||
let item = this.getItem(id);
|
||||
if (item && item.isInventaire()) {
|
||||
const quantite = Math.max(0, item.system.quantite + value);
|
||||
await this.updateEmbeddedDocuments('Item', [{ _id: item.id, 'system.quantite': quantite }]);
|
||||
await item.update({ 'system.quantite': quantite });
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,6 +313,7 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
let fortune = this.getFortune();
|
||||
console.log("payer", game.user.character, depense, fortune);
|
||||
// TODO: passer en handlebars
|
||||
let msg = "";
|
||||
if (fortune >= depense) {
|
||||
await Monnaie.optimiserFortune(this, fortune - depense);
|
||||
@ -180,11 +323,10 @@ export class RdDBaseActor extends Actor {
|
||||
msg = "Vous n'avez pas assez d'argent pour payer cette somme !";
|
||||
}
|
||||
|
||||
let message = {
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: msg
|
||||
};
|
||||
ChatMessage.create(message);
|
||||
})
|
||||
}
|
||||
|
||||
async depenserSols(sols) {
|
||||
@ -204,9 +346,10 @@ export class RdDBaseActor extends Actor {
|
||||
ui.notifications.error(`Impossible d'ajouter un gain de ${sols} <0`);
|
||||
return;
|
||||
}
|
||||
if (fromActorId && !game.user.isGM) {
|
||||
if (fromActorId && !this.isOwner) {
|
||||
RdDBaseActor.remoteActorCall({
|
||||
userId: Misc.connectedGMOrUser(),
|
||||
tokenId: this.token?.id,
|
||||
actorId: this.id,
|
||||
method: 'ajouterSols', args: [sols, fromActorId]
|
||||
});
|
||||
@ -217,7 +360,7 @@ export class RdDBaseActor extends Actor {
|
||||
|
||||
RdDAudio.PlayContextAudio("argent"); // Petit son
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: `Vous avez reçu <strong>${sols} Sols</strong> ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.`
|
||||
});
|
||||
}
|
||||
@ -235,25 +378,23 @@ export class RdDBaseActor extends Actor {
|
||||
ui.notifications.info("Inutile de se vendre à soi-même");
|
||||
return;
|
||||
}
|
||||
if (!Misc.isUniqueConnectedGM()) {
|
||||
if (!Misc.isFirstConnectedGM()) {
|
||||
RdDBaseActor.remoteActorCall({
|
||||
actorId: achat.vendeurId ?? achat.acheteurId,
|
||||
method: 'achatVente',
|
||||
args: [achat]
|
||||
method: 'achatVente', args: [achat]
|
||||
});
|
||||
return;
|
||||
return
|
||||
}
|
||||
const cout = Number(achat.prixTotal ?? 0);
|
||||
const vendeur = achat.vendeurId ? game.actors.get(achat.vendeurId) : undefined;
|
||||
const acheteur = achat.acheteurId ? game.actors.get(achat.acheteurId) : undefined;
|
||||
const quantite = (achat.choix.nombreLots ?? 1) * (achat.vente.tailleLot);
|
||||
const itemVendu = vendeur?.getItem(achat.vente.item._id) ?? game.items.get(achat.vente.item._id) ?? achat.vente.item;
|
||||
const itemVendu = vendeur?.getItem(achat.vente.item._id) ?? game.items.get(achat.vente.item._id);
|
||||
if (!itemVendu) {
|
||||
ui.notifications.warn("Erreur sur achat: rien à acheter<br>Si possible, transmettez les logs de la console aux développeurs");
|
||||
console.log('Erreur sur achat: rien à acheter', achat);
|
||||
ChatUtility.notifyUser(achat.userId, 'warn', vendeur ? `Le vendeur n'a pas plus de ${achat.vente.item.name} !` : `Impossible de retrouver: ${achat.vente.item.name} !`);
|
||||
return;
|
||||
}
|
||||
if (!this.verifierQuantite(vendeur, itemVendu, quantite)) {
|
||||
if (vendeur && !vendeur.verifierQuantite(itemVendu, quantite)) {
|
||||
ChatUtility.notifyUser(achat.userId, 'warn', `Le vendeur n'a pas assez de ${itemVendu.name} !`);
|
||||
return
|
||||
}
|
||||
@ -261,43 +402,42 @@ export class RdDBaseActor extends Actor {
|
||||
ChatUtility.notifyUser(achat.userId, 'warn', `Vous n'avez pas assez d'argent pour payer ${Math.ceil(cout / 100)} sols !`);
|
||||
return;
|
||||
}
|
||||
await this.decrementerVente(vendeur, itemVendu, quantite, cout);
|
||||
if (acheteur) {
|
||||
await acheteur.depenserSols(cout);
|
||||
const createdItemId = await acheteur.creerQuantiteItem(achat.vente.item, quantite);
|
||||
await acheteur.consommerNourritureAchetee(achat, achat.vente, createdItemId);
|
||||
}
|
||||
await vendeur?.vendre(itemVendu, quantite, cout);
|
||||
await acheteur?.acheter(itemVendu, quantite, cout, achat)
|
||||
|
||||
if (cout > 0) {
|
||||
RdDAudio.PlayContextAudio("argent");
|
||||
}
|
||||
const chatAchatItem = duplicate(achat.vente);
|
||||
const chatAchatItem = foundry.utils.duplicate(achat.vente);
|
||||
chatAchatItem.quantiteTotal = quantite;
|
||||
ChatMessage.create({
|
||||
user: achat.userId,
|
||||
speaker: { alias: (acheteur ?? vendeur).name },
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
speaker: { alias: (acheteur ?? vendeur).getAlias() },
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-achat-item.html', chatAchatItem)
|
||||
});
|
||||
|
||||
if (!achat.vente.quantiteIllimite) {
|
||||
if (achat.vente.quantiteNbLots <= achat.choix.nombreLots) {
|
||||
if (achat.vente.nbLots <= achat.choix.nombreLots) {
|
||||
ChatUtility.removeChatMessageId(achat.chatMessageIdVente);
|
||||
}
|
||||
else if (achat.chatMessageIdVente) {
|
||||
achat.vente.properties = itemVendu.getProprietes();
|
||||
achat.vente.quantiteNbLots -= achat.choix.nombreLots;
|
||||
achat.vente.jsondata = JSON.stringify(achat.vente.item);
|
||||
const messageVente = game.messages.get(achat.chatMessageIdVente);
|
||||
messageVente.update({ content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', achat.vente) });
|
||||
messageVente.render(true);
|
||||
await ChatVente.diminuerQuantiteAchatVente(achat.chatMessageIdVente, achat.choix.nombreLots)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async decrementerVente(vendeur, itemVendu, quantite, cout) {
|
||||
if (vendeur) {
|
||||
await vendeur.ajouterSols(cout);
|
||||
await vendeur.decrementerQuantiteItem(itemVendu, quantite);
|
||||
async vendre(item, quantite, cout) {
|
||||
await this.ajouterSols(cout);
|
||||
await this.decrementerQuantiteItem(item, quantite);
|
||||
}
|
||||
|
||||
async acheter(item, quantite, cout, achat) {
|
||||
await this.depenserSols(cout)
|
||||
const createdItemId = await this.creerQuantiteItem(item, quantite)
|
||||
if (achat.choix.consommer && item.type == 'nourritureboisson' && createdItemId != undefined) {
|
||||
achat.choix.doses = achat.choix.nombreLots;
|
||||
await this.consommerNourritureboisson(createdItemId, achat.choix, achat.vente.actingUserId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,36 +445,33 @@ export class RdDBaseActor extends Actor {
|
||||
return this.getFortune() >= cout;
|
||||
}
|
||||
|
||||
verifierQuantite(vendeur, item, quantiteTotal) {
|
||||
const disponible = vendeur?.getQuantiteDisponible(item);
|
||||
return disponible == undefined || disponible >= quantiteTotal;
|
||||
}
|
||||
|
||||
async consommerNourritureAchetee(achat, vente, createdItemId) {
|
||||
if (achat.choix.consommer && vente.item.type == 'nourritureboisson' && createdItemId != undefined) {
|
||||
achat.choix.doses = achat.choix.nombreLots;
|
||||
await this.consommerNourritureboisson(createdItemId, achat.choix, vente.actingUserId);
|
||||
}
|
||||
verifierQuantite(item, quantiteDemande) {
|
||||
const disponible = this.getQuantiteDisponible(item);
|
||||
return disponible == undefined || disponible >= quantiteDemande;
|
||||
}
|
||||
|
||||
async consommerNourritureboisson(itemId, choix, userId) { }
|
||||
|
||||
async decrementerQuantiteItem(item, quantite, options = { supprimerSiZero: true }) {
|
||||
if (item.isService()) {
|
||||
return;
|
||||
}
|
||||
const itemId = item.id;
|
||||
let resteQuantite = (item.system.quantite ?? 1) - quantite;
|
||||
if (resteQuantite <= 0) {
|
||||
if (options.supprimerSiZero) {
|
||||
await this.deleteEmbeddedDocuments("Item", [item.id]);
|
||||
}
|
||||
else {
|
||||
await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': 0 }]);
|
||||
await this.updateEmbeddedDocuments("Item", [{ _id: itemId, 'system.quantite': 0 }]);
|
||||
}
|
||||
if (resteQuantite < 0) {
|
||||
ui.notifications.warn(`La quantité de ${item.name} était insuffisante, l'objet a donc été supprimé`)
|
||||
}
|
||||
}
|
||||
else if (resteQuantite > 0) {
|
||||
const realItem = this.getItem(item.id)
|
||||
realItem.update({ 'system.quantite': resteQuantite });
|
||||
await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': resteQuantite }]);
|
||||
}
|
||||
}
|
||||
@ -346,7 +483,7 @@ export class RdDBaseActor extends Actor {
|
||||
type: item.type,
|
||||
img: item.img,
|
||||
name: item.name,
|
||||
system: mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined })
|
||||
system: foundry.utils.mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined }, { inplace: false })
|
||||
};
|
||||
const newItems = isItemEmpilable ? [baseItem] : Array.from({ length: quantite }, (_, i) => baseItem);
|
||||
const items = await this.createEmbeddedDocuments("Item", newItems);
|
||||
@ -355,14 +492,6 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
computeMalusSurEncombrement() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
getEncombrementMax() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
async computeEncTotal() {
|
||||
if (!this.pack) {
|
||||
this.encTotal = this.items.map(it => it.getEncTotal()).reduce(Misc.sum(), 0);
|
||||
@ -371,6 +500,10 @@ export class RdDBaseActor extends Actor {
|
||||
return 0;
|
||||
}
|
||||
|
||||
getEncTotal() {
|
||||
return Math.floor(this.encTotal ?? 0);
|
||||
}
|
||||
|
||||
async createItem(type, name = undefined) {
|
||||
if (!name) {
|
||||
name = 'Nouveau ' + Misc.typeName('Item', type);
|
||||
@ -383,14 +516,15 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
|
||||
async processDropItem(params) {
|
||||
const targetActorId = this.id;
|
||||
const sourceActorId = params.sourceActorId;
|
||||
const itemId = params.itemId;
|
||||
const destId = params.destId;
|
||||
const srcId = params.srcId;
|
||||
const targetActorId = this.id
|
||||
const sourceActorId = params.sourceActorId
|
||||
const sourceTokenId = params.sourceTokenId
|
||||
const itemId = params.itemId
|
||||
const destId = params.destId
|
||||
const srcId = params.srcId
|
||||
if (sourceActorId && sourceActorId != targetActorId) {
|
||||
console.log("Moving objects", sourceActorId, targetActorId, itemId);
|
||||
this.moveItemsBetweenActors(itemId, sourceActorId);
|
||||
console.log("Moving objects", sourceActorId, sourceTokenId, targetActorId, itemId);
|
||||
this.moveItemsBetweenActors(itemId, sourceActorId, sourceTokenId);
|
||||
return false;
|
||||
}
|
||||
let result = true;
|
||||
@ -435,77 +569,45 @@ export class RdDBaseActor extends Actor {
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
conteneurPeutContenir(dest, item) {
|
||||
conteneurPeutContenir(dest, moved) {
|
||||
if (!dest) {
|
||||
return true;
|
||||
}
|
||||
if (!dest.isConteneur()) {
|
||||
return false;
|
||||
}
|
||||
const destData = dest
|
||||
if (this._isConteneurContenu(item, dest)) {
|
||||
ui.notifications.warn(`Impossible de déplacer un conteneur parent (${item.name}) dans un de ses contenus ${destData.name} !`);
|
||||
return false; // Loop detected !
|
||||
if (moved.isConteneurContenu(dest)) {
|
||||
ui.notifications.warn(`Impossible de déplacer un conteneur parent (${moved.name}) dans un de ses contenus ${dest.name} !`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculer le total actuel des contenus
|
||||
let encContenu = this.getRecursiveEnc(dest) - Number(destData.system.encombrement);
|
||||
let newEnc = this.getRecursiveEnc(item); // Calculer le total actuel du nouvel objet
|
||||
const encContenu = dest.getEncContenu();
|
||||
const newEnc = moved.getEncTotal(); // Calculer le total actuel du nouvel objet
|
||||
const placeDisponible = Misc.keepDecimals(dest.system.capacite - encContenu - newEnc, 4)
|
||||
|
||||
// Teste si le conteneur de destination a suffisament de capacité pour recevoir le nouvel objet
|
||||
if (Number(destData.system.capacite) < encContenu + newEnc) {
|
||||
if (placeDisponible < 0) {
|
||||
ui.notifications.warn(
|
||||
`Le conteneur ${dest.name} a une capacité de ${destData.system.capacite}, et contient déjà ${encContenu}.
|
||||
Impossible d'y ranger: ${item.name} d'encombrement ${newEnc}!`);
|
||||
`Le conteneur ${dest.name} a une capacité de ${dest.system.capacite}, et contient déjà ${encContenu}.
|
||||
Impossible d'y ranger: ${moved.name} d'encombrement ${newEnc}!`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_isConteneurContenu(item, conteneur) {
|
||||
if (item?.isConteneur()) { // Si c'est un conteneur, il faut vérifier qu'on ne le déplace pas vers un sous-conteneur lui appartenant
|
||||
for (let id of item.system.contenu) {
|
||||
let subObjet = this.getItem(id);
|
||||
if (subObjet?.id == conteneur.id) {
|
||||
return true; // Loop detected !
|
||||
}
|
||||
if (subObjet?.isConteneur()) {
|
||||
return this._isConteneurContenu(subObjet, conteneur);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getRecursiveEnc(objet) {
|
||||
if (!objet) {
|
||||
return 0;
|
||||
}
|
||||
const tplData = objet.system;
|
||||
if (objet.type != 'conteneur') {
|
||||
return Number(tplData.encombrement) * Number(tplData.quantite);
|
||||
}
|
||||
const encContenus = tplData.contenu.map(idContenu => this.getRecursiveEnc(this.getItem(idContenu)));
|
||||
return encContenus.reduce(Misc.sum(), 0)
|
||||
+ Number(tplData.encombrement) /* TODO? Number(tplData.quantite) -- on pourrait avoir plusieurs conteneurs...*/
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** Ajoute un item dans un conteneur, sur la base
|
||||
* de leurs ID */
|
||||
/** Ajoute un item dans un conteneur, sur la base de leurs ID */
|
||||
async ajouterDansConteneur(item, conteneur, onAjouterDansConteneur) {
|
||||
if (!conteneur) {
|
||||
// TODO: afficher
|
||||
item.estContenu = false;
|
||||
}
|
||||
else if (conteneur.isConteneur()) {
|
||||
if (conteneur?.isConteneur()) {
|
||||
item.estContenu = true;
|
||||
await this.updateEmbeddedDocuments('Item', [{
|
||||
_id: conteneur.id,
|
||||
'system.contenu': [...conteneur.system.contenu, item.id]
|
||||
}]);
|
||||
onAjouterDansConteneur(item.id, conteneur.id);
|
||||
const nouveauContenu = [...conteneur.system.contenu, item.id];
|
||||
await conteneur.update({ 'system.contenu': nouveauContenu });
|
||||
onAjouterDansConteneur(item.id, conteneur.id)
|
||||
}
|
||||
else {
|
||||
item.estContenu = false;
|
||||
await conteneur?.update({ 'system.-=contenu': undefined })
|
||||
}
|
||||
}
|
||||
|
||||
@ -523,8 +625,13 @@ export class RdDBaseActor extends Actor {
|
||||
if (item.estContenu) {
|
||||
item.estContenu = undefined;
|
||||
}
|
||||
if (item.type == 'conteneur' && item.system.contenu.length > 0) {
|
||||
corrections.push({ _id: item.id, 'system.contenu': [] });
|
||||
if (item.system.contenu != undefined) {
|
||||
if (item.type == 'conteneur') {
|
||||
corrections.push({ _id: item.id, 'system.contenu': [] });
|
||||
}
|
||||
else {
|
||||
corrections.push({ _id: item.id, 'system.-=contenu': undefined });
|
||||
}
|
||||
}
|
||||
}
|
||||
if (corrections.length > 0) {
|
||||
@ -559,28 +666,31 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** Supprime un item d'un conteneur, sur la base
|
||||
* de leurs ID */
|
||||
/**
|
||||
* Supprime un item d'un conteneur, sur la base de leurs ID
|
||||
*/
|
||||
async enleverDeConteneur(item, conteneur, onEnleverDeConteneur) {
|
||||
if (conteneur?.isConteneur()) {
|
||||
item.estContenu = false;
|
||||
await this.updateEmbeddedDocuments('Item', [{
|
||||
_id: conteneur.id,
|
||||
'system.contenu': conteneur.system.contenu.filter(id => id != item.id)
|
||||
}]);
|
||||
onEnleverDeConteneur();
|
||||
if (conteneur) {
|
||||
if (conteneur.isConteneur()) {
|
||||
const contenu = conteneur.system.contenu.filter(id => id != item.id);
|
||||
await conteneur.update({ 'system.contenu': contenu });
|
||||
onEnleverDeConteneur();
|
||||
}
|
||||
else {
|
||||
await conteneur.update({ 'system.-=contenu': undefined })
|
||||
}
|
||||
}
|
||||
item.estContenu = false;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async moveItemsBetweenActors(itemId, sourceActorId) {
|
||||
let itemsList = []
|
||||
let sourceActor = game.actors.get(sourceActorId);
|
||||
itemsList.push({ id: itemId, conteneurId: undefined }); // Init list
|
||||
async moveItemsBetweenActors(itemId, sourceActorId, sourceTokenId) {
|
||||
let sourceActor = RdDBaseActor.getRealActor(sourceActorId, sourceTokenId)
|
||||
let itemsList = [{ id: itemId, conteneurId: undefined }]
|
||||
sourceActor.buildSubConteneurObjetList(itemId, itemsList); // Get itemId list
|
||||
|
||||
const itemsDataToCreate = itemsList.map(it => sourceActor.getItem(it.id))
|
||||
.map(it => duplicate(it))
|
||||
.map(it => foundry.utils.duplicate(it))
|
||||
.map(it => { it.system.contenu = []; return it; });
|
||||
let newItems = await this.createEmbeddedDocuments('Item', itemsDataToCreate);
|
||||
|
||||
@ -589,20 +699,17 @@ export class RdDBaseActor extends Actor {
|
||||
for (let item of itemsList) { // Second boucle pour traiter la remise en conteneurs
|
||||
// gestion conteneur/contenu
|
||||
if (item.conteneurId) { // l'Objet était dans un conteneur
|
||||
let newConteneurId = itemMap[item.conteneurId]; // Get conteneur
|
||||
let newConteneur = this.getItem(newConteneurId);
|
||||
|
||||
let newItemId = itemMap[item.id]; // Get newItem
|
||||
const newConteneurId = itemMap[item.conteneurId];
|
||||
const newConteneur = this.getItem(newConteneurId);
|
||||
const newItemId = itemMap[item.id]; // Get newItem
|
||||
|
||||
console.log('New conteneur filling!', newConteneur, newItemId, item);
|
||||
let contenu = duplicate(newConteneur.system.contenu);
|
||||
contenu.push(newItemId);
|
||||
await this.updateEmbeddedDocuments('Item', [{ _id: newConteneurId, 'system.contenu': contenu }]);
|
||||
const nouveauContenu = [...newConteneur.system.contenu, newItemId]
|
||||
await newConteneur.update({ 'system.contenu': nouveauContenu })
|
||||
}
|
||||
}
|
||||
for (let item of itemsList) {
|
||||
await sourceActor.deleteEmbeddedDocuments('Item', [item.id]);
|
||||
}
|
||||
const deletedItemIds = itemsList.map(it => it.id)
|
||||
await sourceActor.deleteEmbeddedDocuments('Item', deletedItemIds);
|
||||
}
|
||||
|
||||
_buildMapOldNewId(itemsList, newItems) {
|
||||
@ -621,12 +728,41 @@ export class RdDBaseActor extends Actor {
|
||||
type: this.type,
|
||||
img: this.img,
|
||||
pack: this.pack,
|
||||
name: this.name,
|
||||
name: this.getAlias(),
|
||||
system: { description: this.system.description }
|
||||
}
|
||||
renderTemplate('systems/foundryvtt-reve-de-dragon/templates/post-actor.html', chatData)
|
||||
.then(html => ChatMessage.create(RdDUtility.chatDataSetup(html, modeOverride)));
|
||||
}
|
||||
|
||||
actionImpossible(action) {
|
||||
ui.notifications.info(`${this.getAlias()} ne peut pas faire cette action: ${action}`)
|
||||
}
|
||||
|
||||
async jetEthylisme() { this.actionImpossible("jet d'éthylisme") }
|
||||
async rollAppelChance() { this.actionImpossible("appel à la chance") }
|
||||
async jetDeMoral() { this.actionImpossible("jet de moral") }
|
||||
|
||||
async resetItemUse() { }
|
||||
async incDecItemUse(itemId, inc = 1) { }
|
||||
getItemUse(itemId) { return 0; }
|
||||
|
||||
async finDeRound(options = { terminer: false }) { }
|
||||
isActorCombat() { return false }
|
||||
getCaracInit(competence) { return 0 }
|
||||
|
||||
listActionsCombat() { return [] }
|
||||
listActionsPossessions() {
|
||||
return this.itemTypes[ITEM_TYPES.possession]
|
||||
.map(p => {
|
||||
return {
|
||||
name: p.name,
|
||||
action: 'possession',
|
||||
system: {
|
||||
competence: p.name,
|
||||
possessionid: p.system.possessionid,
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
import { DialogItemAchat } from "../dialog-item-achat.js";
|
||||
import { DialogItemAchat } from "../achat-vente/dialog-item-achat.js";
|
||||
import { RdDItem } from "../item.js";
|
||||
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
import { RdDBaseActorSheet } from "./base-actor-sheet.js";
|
||||
import { RdDCommerce } from "./commerce.js";
|
||||
|
||||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
@ -13,14 +11,11 @@ export class RdDCommerceSheet extends RdDBaseActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["rdd", "sheet", "actor"],
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-actor-sheet.html",
|
||||
width: 600,
|
||||
height: 720,
|
||||
tabs: [],
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
|
||||
});
|
||||
width: 600, height: 720,
|
||||
tabs: []
|
||||
}, { inplace: false })
|
||||
}
|
||||
get title() {
|
||||
if (this.actor.token && this.actor.token != this.actor.prototypeToken) {
|
||||
@ -32,7 +27,7 @@ export class RdDCommerceSheet extends RdDBaseActorSheet {
|
||||
async getData() {
|
||||
const formData = await super.getData();
|
||||
if (this.actor.token && this.actor.token != this.actor.prototypeToken) {
|
||||
mergeObject(formData,
|
||||
foundry.utils.mergeObject(formData,
|
||||
{
|
||||
title: this.actor.token.name,
|
||||
token: {
|
||||
@ -50,6 +45,7 @@ export class RdDCommerceSheet extends RdDBaseActorSheet {
|
||||
super.activateListeners(html);
|
||||
|
||||
this.html.find('a.item-acheter').click(async event => await this.vente(this.getItem(event)));
|
||||
this.html.find('.service-acheter').click(async event => await this.vente(this.getItem(event)));
|
||||
|
||||
if (!this.options.editable) return;
|
||||
|
||||
@ -78,7 +74,7 @@ export class RdDCommerceSheet extends RdDBaseActorSheet {
|
||||
}
|
||||
const disponible = this.actor.getQuantiteDisponible(item)
|
||||
if (disponible == 0) {
|
||||
ui.notifications.warn(`${this.name} n'a plus de ${item.name} en vente`);
|
||||
ui.notifications.warn(`${this.getAlias()} n'a plus de ${item.name} en vente`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -7,27 +7,18 @@ export class RdDCommerce extends RdDBaseActor {
|
||||
return "systems/foundryvtt-reve-de-dragon/icons/services/commerce.webp";
|
||||
}
|
||||
|
||||
prepareData() {
|
||||
super.prepareData();
|
||||
}
|
||||
prepareDerivedData() {
|
||||
super.prepareDerivedData();
|
||||
}
|
||||
|
||||
canReceive(item) {
|
||||
if (item.isInventaire('all')) {
|
||||
return true;
|
||||
}
|
||||
return super.canReceive(item);
|
||||
return item.isInventaire('all');
|
||||
}
|
||||
|
||||
getQuantiteDisponible(item) {
|
||||
return this.system.illimite || item.isService() ? undefined : item.getQuantite();
|
||||
return (this.system.illimite || item?.isService()) ? undefined : item.getQuantite();
|
||||
}
|
||||
|
||||
verifierFortune(cout) {
|
||||
return this.system.illimite || super.verifierFortune(cout);
|
||||
}
|
||||
|
||||
async depenserSols(cout) {
|
||||
if (this.system.illimite) {
|
||||
return
|
||||
@ -35,10 +26,6 @@ export class RdDCommerce extends RdDBaseActor {
|
||||
await super.depenserSols(cout)
|
||||
}
|
||||
|
||||
async consommerNourritureAchetee(achat, vente, createdItemId) {
|
||||
// ne pas consommer pour un commerce
|
||||
}
|
||||
|
||||
async decrementerQuantiteItem(item, quantite) {
|
||||
if (this.system.illimite) {
|
||||
return;
|
||||
|
@ -1,21 +1,18 @@
|
||||
import { RdDActorSheet } from "./actor-sheet.js";
|
||||
import { RdDBaseActorReveSheet } from "./base-actor-reve-sheet.js";
|
||||
import { RdDBaseActorSangSheet } from "./base-actor-sang-sheet.js";
|
||||
|
||||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
* @extends {ActorSheet}
|
||||
*/
|
||||
export class RdDActorCreatureSheet extends RdDActorSheet {
|
||||
export class RdDCreatureSheet extends RdDBaseActorSangSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["rdd", "sheet", "actor"],
|
||||
return foundry.utils.mergeObject(RdDBaseActorSangSheet.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor-creature-sheet.html",
|
||||
width: 640,
|
||||
height: 720,
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
|
||||
});
|
||||
width: 640, height: 720
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
49
module/actor/creature.js
Normal file
@ -0,0 +1,49 @@
|
||||
import { Grammar } from "../grammar.js";
|
||||
import { ITEM_TYPES } from "../constants.js";
|
||||
import { LIST_CARAC_AUTRES } from "../rdd-carac.js";
|
||||
import { RdDBaseActorSang } from "./base-actor-sang.js";
|
||||
|
||||
export class RdDCreature extends RdDBaseActorSang {
|
||||
|
||||
static get defaultIcon() {
|
||||
return "systems/foundryvtt-reve-de-dragon/icons/creatures/bramart.svg";
|
||||
}
|
||||
|
||||
getEnduranceMax() { return Math.max(1, this.getVieMax() + this.getConstitution()) }
|
||||
isCreature() { return true }
|
||||
|
||||
canReceive(item) {
|
||||
return item.type == ITEM_TYPES.competencecreature || item.isInventaire();
|
||||
}
|
||||
|
||||
async remiseANeuf() {
|
||||
await this.removeEffects(e => true);
|
||||
await this.supprimerBlessures(it => true);
|
||||
await this.update({
|
||||
'system.sante.endurance.value': this.system.sante.endurance.max,
|
||||
'system.sante.vie.value': this.system.sante.vie.max,
|
||||
'system.sante.fatigue.value': 0
|
||||
});
|
||||
}
|
||||
|
||||
async finDeRoundBlessures() {
|
||||
const nbGraves = this.filterItems(it => it.isGrave(), 'blessure').length;
|
||||
if (nbGraves > 0) {
|
||||
// Gestion blessure graves : -1 pt endurance par blessure grave
|
||||
await this.santeIncDec("endurance", -nbGraves);
|
||||
}
|
||||
}
|
||||
|
||||
mapCarac(caracCode) {
|
||||
switch (caracCode) {
|
||||
case 'vue': case 'ouie': case 'odoratgout': case 'empathie': case 'perception':
|
||||
return 'perception'
|
||||
case 'agilite':
|
||||
return 'force'
|
||||
case 'force': case 'constitution': case 'taille': case 'reve': case 'volonte':
|
||||
return caracCode
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
}
|
80
module/actor/entite-sheet.js
Normal file
@ -0,0 +1,80 @@
|
||||
import { RdDBaseActorReveSheet } from "./base-actor-reve-sheet.js";
|
||||
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
import { DialogSelect } from "../dialog-select.js";
|
||||
|
||||
export class RdDActorEntiteSheet extends RdDBaseActorReveSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(RdDBaseActorReveSheet.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html",
|
||||
width: 640, height: 720,
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
async getData() {
|
||||
let formData = await super.getData();
|
||||
formData.niveau = this.actor.getNiveau()
|
||||
delete formData.system.carac.niveau
|
||||
formData.resonances = this.actor.system.sante.resonnance.actors.map(actorId => game.actors.get(actorId))
|
||||
.map(actor => { return { id: actor.id, name: actor.name, img: actor.img } })
|
||||
return formData
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
// On competence change
|
||||
this.html.find('.creature-carac').change(async event => {
|
||||
let compName = event.currentTarget.attributes.compname.value;
|
||||
this.actor.updateCreatureCompetence(compName, "carac_value", parseInt(event.target.value));
|
||||
});
|
||||
this.html.find('.creature-dommages').change(async event => {
|
||||
let compName = event.currentTarget.attributes.compname.value;
|
||||
this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value));
|
||||
})
|
||||
|
||||
this.html.find('.resonance-add').click(async event =>
|
||||
DialogSelect.select({
|
||||
label: "Choisir un acteur à accorder",
|
||||
list: game.actors.filter(it => it.isPersonnage() && it.prototypeToken.actorLink)
|
||||
},
|
||||
it => this.resonanceAdd(it.id))
|
||||
)
|
||||
|
||||
this.html.find('.resonance-delete').click(async event => {
|
||||
const li = RdDSheetUtility.getEventElement(event);
|
||||
const actorId = li.data("actor-id");
|
||||
if (actorId) {
|
||||
const actorResonance = game.actors.get(actorId);
|
||||
RdDUtility.confirmSubActeurDelete(this, actorResonance, li, () => {
|
||||
this.resonanceDelete(actorId);
|
||||
RdDUtility.slideOnDelete(this, li);
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async _onDropActor(event, dragData) {
|
||||
const dropActor = fromUuidSync(dragData.uuid)
|
||||
await this.actor.setEntiteReveAccordee(dropActor)
|
||||
super._onDropActor(event, dragData)
|
||||
}
|
||||
|
||||
async resonanceAdd(actorId) {
|
||||
let newResonances = [...this.actor.system.sante.resonnance.actors, actorId]
|
||||
await this.actor.update({ 'system.sante.resonnance.actors': newResonances });
|
||||
}
|
||||
|
||||
async resonanceDelete(actorId) {
|
||||
console.log('Delete : ', actorId);
|
||||
let newResonances = this.actor.system.sante.resonnance.actors.filter(id => id != actorId);
|
||||
await this.actor.update({ 'system.sante.resonnance.actors': newResonances }, { renderSheet: false });
|
||||
}
|
||||
}
|
130
module/actor/entite.js
Normal file
@ -0,0 +1,130 @@
|
||||
import { ENTITE_INCARNE, ENTITE_NONINCARNE } from "../constants.js";
|
||||
import { ITEM_TYPES } from "../constants.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { RdDCarac } from "../rdd-carac.js";
|
||||
import { RdDEncaisser } from "../rdd-roll-encaisser.js";
|
||||
import { STATUSES } from "../settings/status-effects.js";
|
||||
import { RdDBaseActorReve } from "./base-actor-reve.js";
|
||||
|
||||
export class RdDEntite extends RdDBaseActorReve {
|
||||
|
||||
static get defaultIcon() {
|
||||
return "systems/foundryvtt-reve-de-dragon/icons/entites/darquoine.webp";
|
||||
}
|
||||
|
||||
canReceive(item) {
|
||||
return item.type == ITEM_TYPES.competencecreature
|
||||
}
|
||||
|
||||
isEntite(typeentite = []) {
|
||||
return (typeentite.length == 0 || typeentite.includes(this.system.definition.typeentite));
|
||||
}
|
||||
|
||||
isNonIncarnee() { return this.isEntite([ENTITE_NONINCARNE]) }
|
||||
|
||||
getReveActuel() {
|
||||
return Misc.toInt(this.system.carac.reve?.value)
|
||||
}
|
||||
|
||||
getCarac() {
|
||||
const carac = super.getCarac()
|
||||
delete carac.niveau
|
||||
return carac
|
||||
}
|
||||
|
||||
getNiveau() {
|
||||
const reve = this.getReve()
|
||||
return RdDCarac.getCaracDerivee(reve).niveau
|
||||
}
|
||||
getForce() { return this.getReve() }
|
||||
getAgilite() { return this.getReve() }
|
||||
getChance() { return this.getReve() }
|
||||
getEnduranceMax() { return Math.max(1, this.getTaille() + this.getReve()) }
|
||||
|
||||
getDraconicOuPossession() {
|
||||
return this.itemTypes[ITEM_TYPES.competencecreature]
|
||||
.filter(it => it.system.categorie == 'possession')
|
||||
.sort(Misc.descending(it => it.system.niveau))
|
||||
.find(it => true);
|
||||
}
|
||||
|
||||
async remiseANeuf() {
|
||||
await this.removeEffects(e => true);
|
||||
if (!this.isNonIncarnee()) {
|
||||
await this.update({
|
||||
'system.sante.endurance.value': this.system.sante.endurance.max
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
isDead() {
|
||||
return this.isNonIncarnee() ? false : this.system.sante.endurance.value <= 0
|
||||
}
|
||||
|
||||
async santeIncDec(name, inc, isCritique = false) {
|
||||
if (name == 'endurance' && !this.isNonIncarnee()) {
|
||||
const oldValue = this.system.sante.endurance.value;
|
||||
const endurance = Math.max(0,
|
||||
Math.min(oldValue + inc,
|
||||
this.system.sante.endurance.max));
|
||||
await this.update({ "system.sante.endurance.value": endurance })
|
||||
await this.setEffect(STATUSES.StatusComma, endurance <= 0);
|
||||
return {
|
||||
perte: oldValue - endurance,
|
||||
newValue: endurance
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
async encaisser() {
|
||||
if (this.isNonIncarnee()) {
|
||||
return
|
||||
}
|
||||
await RdDEncaisser.encaisser(this)
|
||||
}
|
||||
|
||||
isEffectAllowed(effectId) {
|
||||
return [STATUSES.StatusComma].includes(effectId);
|
||||
}
|
||||
|
||||
async onAppliquerJetEncaissement(encaissement, attackerToken) {
|
||||
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance);
|
||||
foundry.utils.mergeObject(encaissement, {
|
||||
resteEndurance: perteEndurance.newValue,
|
||||
endurance: perteEndurance.perte
|
||||
});
|
||||
}
|
||||
|
||||
isEntiteAccordee(attacker) {
|
||||
if (this.isEntite([ENTITE_INCARNE])) {
|
||||
let resonnance = this.system.sante.resonnance
|
||||
return (resonnance.actors.find(it => it == attacker.id))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async setEntiteReveAccordee(actor) {
|
||||
if (this.isEntite([ENTITE_INCARNE])) {
|
||||
if (this.system.sante.resonnance.actors.find(it => it == actor.id)) {
|
||||
// déjà accordé
|
||||
return
|
||||
}
|
||||
await this.update({ "system.sante.resonnance.actors": [...this.system.sante.resonnance.actors, actor.id] })
|
||||
}
|
||||
else {
|
||||
super.setEntiteReveAccordee(actor)
|
||||
}
|
||||
}
|
||||
|
||||
mapCarac(caracCode) {
|
||||
switch (caracCode) {
|
||||
case 'taille':
|
||||
case 'reve':
|
||||
return caracCode
|
||||
}
|
||||
return 'reve'
|
||||
}
|
||||
|
||||
}
|
39
module/actor/experience-log.js
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
export const XP_TOPIC = {
|
||||
XP: { code: 'xp', label: 'xp' },
|
||||
XPSORT: { code: 'xpsort', label: 'xp sort' },
|
||||
NIVEAU: { code: 'niveau', label: 'Niveau' },
|
||||
XPCARAC: { code: 'xpcarac', label: 'xp carac' },
|
||||
CARAC: { code: 'carac', label: 'Carac' },
|
||||
STRESS: { code: 'stress', label: 'Stress' },
|
||||
TRANSFORM: { code: 'xps', label: 'Transformé' },
|
||||
}
|
||||
|
||||
export class ExperienceLog {
|
||||
|
||||
static async add(actor, topic, from, to, raison, manuel = false) {
|
||||
if (!actor.isPersonnageJoueur()) {
|
||||
return
|
||||
}
|
||||
if (from == to) {
|
||||
return
|
||||
}
|
||||
const newXpLog = {
|
||||
mode: topic?.code ?? topic,
|
||||
raison: (manuel ? '(manuel) ' : '') + raison,
|
||||
from: from,
|
||||
to: to,
|
||||
valeur: to - from,
|
||||
daterdd: game.system.rdd.calendrier.dateCourante(),
|
||||
datereel: game.system.rdd.calendrier.dateReel().replace('T', ' ')
|
||||
};
|
||||
console.log('ExperienceLog.add', newXpLog)
|
||||
const newExperienceLog = (actor.system.experiencelog ?? []).concat([newXpLog]);
|
||||
await actor.update({ [`system.experiencelog`]: newExperienceLog });
|
||||
}
|
||||
|
||||
static labelTopic(topic) {
|
||||
const xpt = Object.values(XP_TOPIC).find(it => it.code == topic);
|
||||
return xpt?.label ?? xpt?.code ?? topic;
|
||||
}
|
||||
}
|
116
module/actor/export-scriptarium/actor-encart-sheet.js
Normal file
@ -0,0 +1,116 @@
|
||||
import { RdDActorSheet } from "../../actor-sheet.js"
|
||||
import { SYSTEM_RDD } from "../../constants.js";
|
||||
import { Misc } from "../../misc.js";
|
||||
import { EXPORT_CSV_SCRIPTARIUM, OptionsAvancees } from "../../settings/options-avancees.js";
|
||||
import { ExportScriptarium } from "./export-scriptarium.js";
|
||||
import { CATEGORIES_COMPETENCES, CATEGORIES_DRACONIC, Mapping } from "./mapping.js";
|
||||
|
||||
export class RdDActorExportSheet extends RdDActorSheet {
|
||||
static init() {
|
||||
loadTemplates([
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/arme.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/blessure.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/blessures.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-compteur.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-derivee.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-derivee-compteur.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/competences.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/esquive.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/fatigue.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/protection.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs",
|
||||
])
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDActorExportSheet, { types: ["personnage"], makeDefault: false, label: "Feuille simplifiée" })
|
||||
}
|
||||
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(RdDActorSheet.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/actor-encart-sheet.hbs",
|
||||
width: 550,
|
||||
showCompNiveauBase: false,
|
||||
vueArchetype: false,
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
constructor(actor, options) {
|
||||
super(actor, options)
|
||||
}
|
||||
|
||||
async getData() {
|
||||
const formData = await super.getData()
|
||||
// Add any structured, precomputed list of data
|
||||
formData.context = Mapping.prepareContext(this.actor)
|
||||
formData.export = this.getMappingValues(formData.context, this.actor)
|
||||
formData.competences = this.getCompetences(CATEGORIES_COMPETENCES)
|
||||
formData.draconic = this.getCompetences(CATEGORIES_DRACONIC)
|
||||
const legeres = this.actor.nbBlessuresLegeres()
|
||||
const graves = this.actor.nbBlessuresGraves()
|
||||
const critiques = this.actor.nbBlessuresCritiques()
|
||||
formData.etat = {
|
||||
surenc: this.actor.computeMalusSurEncombrement(),
|
||||
fatigue: {
|
||||
value: this.actor.getFatigueActuelle(),
|
||||
max: this.actor.getFatigueMax(),
|
||||
malus: this.actor.malusFatigue()
|
||||
},
|
||||
blessures: legeres + graves + critiques,
|
||||
blessure: [legeres > 0, legeres > 1, legeres > 2, legeres > 3, legeres > 4, graves > 0, graves > 1, critiques > 0],
|
||||
}
|
||||
formData.options.exportScriptarium = OptionsAvancees.isUsing(EXPORT_CSV_SCRIPTARIUM)
|
||||
return formData
|
||||
}
|
||||
|
||||
getMappingValues(context, actor) {
|
||||
return Object.fromEntries(Mapping.getMapping().map(it => [it.column, {
|
||||
colName: it.colName ?? it.column,
|
||||
column: it.column,
|
||||
rollClass: it.rollClass,
|
||||
value: String(it.getter(actor, context))
|
||||
}]))
|
||||
}
|
||||
|
||||
getCompetences(categories) {
|
||||
const competences = Mapping.getCompetencesCategorie(this.actor, categories)
|
||||
if (competences.length == 0) {
|
||||
return ''
|
||||
}
|
||||
const byCategories = Mapping.competencesByCategoriesByNiveau(competences, categories)
|
||||
const listByCategories = Object.values(byCategories)
|
||||
.map(it => it.competencesParNiveau)
|
||||
.map(byNiveau => {
|
||||
const niveaux = Object.keys(byNiveau).map(it => Number(it)).sort(Misc.ascending())
|
||||
if (niveaux.length == 0) {
|
||||
return undefined
|
||||
}
|
||||
const listCategorieByNiveau = niveaux.map(niveau => {
|
||||
const list = byNiveau[niveau].sort(Misc.ascending(it => it.name))
|
||||
return { niveau, list }
|
||||
})
|
||||
return Misc.concat(listCategorieByNiveau)
|
||||
}).filter(it => it != undefined)
|
||||
|
||||
return Misc.concat(listByCategories)
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
this.html.find('.click-blessure-remove').click(async event =>
|
||||
await this.actor.supprimerBlessure({
|
||||
gravite: this.html.find(event.currentTarget).data('gravite')
|
||||
})
|
||||
)
|
||||
this.html.find('.click-blessure-add').click(async event =>
|
||||
await this.actor.ajouterBlessure({
|
||||
gravite: this.html.find(event.currentTarget).data('gravite')
|
||||
// event.currentTarget.attributes['data-gravite'].value
|
||||
})
|
||||
)
|
||||
this.html.find('.button-export').click(async event => {
|
||||
ExportScriptarium.INSTANCE.exportActors([this.actor],
|
||||
`${this.actor.uuid}-${this.actor.name}`
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
78
module/actor/export-scriptarium/export-scriptarium.js
Normal file
@ -0,0 +1,78 @@
|
||||
import { ACTOR_TYPES } from "../../constants.js"
|
||||
import { Misc } from "../../misc.js"
|
||||
import { EXPORT_CSV_SCRIPTARIUM, OptionsAvancees } from "../../settings/options-avancees.js"
|
||||
import { Mapping } from "./mapping.js"
|
||||
|
||||
const IMG_SCRIPTARIUM = '<img class="context-menu-img" src="systems/foundryvtt-reve-de-dragon/styles/img/ui/scriptarium.svg">'
|
||||
|
||||
export class ExportScriptarium {
|
||||
|
||||
static init() {
|
||||
ExportScriptarium.INSTANCE = new ExportScriptarium()
|
||||
}
|
||||
|
||||
constructor() {
|
||||
Hooks.on("getActorDirectoryFolderContext", (actorDirectory, menus) => { ExportScriptarium.INSTANCE.onActorDirectoryMenu(actorDirectory, menus) })
|
||||
Hooks.on("getActorDirectoryEntryContext", (actorDirectory, menus) => { ExportScriptarium.INSTANCE.onActorDirectoryMenu(actorDirectory, menus) })
|
||||
}
|
||||
|
||||
onActorDirectoryMenu(actorDirectory, menus) {
|
||||
menus.push({
|
||||
name: 'Export Personnages <i class="fa-regular fa-file-csv"></i>',
|
||||
icon: IMG_SCRIPTARIUM,
|
||||
condition: (target) => game.user.isGM &&
|
||||
OptionsAvancees.isUsing(EXPORT_CSV_SCRIPTARIUM) &&
|
||||
this.$getActors(actorDirectory, target).length > 0,
|
||||
callback: target => this.exportActors(this.$getActors(actorDirectory, target), this.$getTargetName(actorDirectory, target))
|
||||
})
|
||||
}
|
||||
|
||||
$getTargetName(actorDirectory, target) {
|
||||
const li = target.closest(".directory-item")
|
||||
const folderId = li.data("folderId")
|
||||
const actorId = li.data("documentId")
|
||||
return actorId
|
||||
? game.actors.get(actorId).name
|
||||
: actorDirectory.folders.find(it => it.id == folderId).name
|
||||
}
|
||||
|
||||
$getActors(actorDirectory, target) {
|
||||
const li = target.closest(".directory-item")
|
||||
const folderId = li.data("folderId")
|
||||
const actorId = li.data("documentId")
|
||||
const actors = actorId
|
||||
? [game.actors.get(actorId)]
|
||||
: folderId
|
||||
? actorDirectory.folders.find(it => it.id == folderId).contents
|
||||
: []
|
||||
return actors.filter(it => it.type == ACTOR_TYPES.personnage)
|
||||
}
|
||||
|
||||
exportActors(actors, targetName) {
|
||||
const eol = '\n\r'
|
||||
const header = Misc.join(this.getHeaderLine(), ';')
|
||||
const actorLines = actors.map(actor => Misc.join(this.getActorLine(actor), ';'))
|
||||
const data = Misc.join([header, ...actorLines], eol)
|
||||
const filename = `scriptarium-${targetName?.slugify()}.csv`;
|
||||
saveDataToFile(data, "text/csv;charset=windows-1252", `${filename}`);
|
||||
}
|
||||
|
||||
getHeaderLine() {
|
||||
return Mapping.getColumns()
|
||||
}
|
||||
|
||||
getActorLine(actor) {
|
||||
const values = Mapping.getValues(actor)
|
||||
return values
|
||||
.map(it => this.$escapeQuotes(it))
|
||||
.map(it => it.replaceAll("\n", " ").replaceAll("\r", ""))
|
||||
}
|
||||
|
||||
$escapeQuotes(it) {
|
||||
it = '' + it
|
||||
if (it.includes('"') || it.includes(';')) {
|
||||
return `"${it.replaceAll('"', '\\"')}"`
|
||||
}
|
||||
return it
|
||||
}
|
||||
}
|
381
module/actor/export-scriptarium/mapping.js
Normal file
@ -0,0 +1,381 @@
|
||||
import { Grammar } from "../../grammar.js"
|
||||
import { RdDItemArme } from "../../item-arme.js"
|
||||
import { RdDItemCompetence } from "../../item-competence.js"
|
||||
import { RdDItemSort } from "../../item-sort.js"
|
||||
import { ITEM_TYPES } from "../../constants.js"
|
||||
import { Misc } from "../../misc.js"
|
||||
import { RdDTimestamp } from "../../time/rdd-timestamp.js"
|
||||
import { RdDBonus } from "../../rdd-bonus.js"
|
||||
import { TMRType } from "../../tmr-utility.js"
|
||||
|
||||
|
||||
export const CATEGORIES_COMPETENCES = [
|
||||
"generale",
|
||||
"particuliere",
|
||||
"specialisee",
|
||||
"connaissance",
|
||||
]
|
||||
export const CATEGORIES_DRACONIC = [
|
||||
"draconic",
|
||||
]
|
||||
|
||||
const CATEGORIES_COMBAT = [
|
||||
"melee",
|
||||
"tir",
|
||||
"lancer"
|
||||
]
|
||||
|
||||
const NIVEAU_BASE = {
|
||||
"generale": -4,
|
||||
"particuliere": -8,
|
||||
"specialisee": -11,
|
||||
"connaissance": -11,
|
||||
"draconic": -11,
|
||||
"melee": -6,
|
||||
"tir": -8,
|
||||
"lancer": -8,
|
||||
}
|
||||
|
||||
class ColumnMappingFactory {
|
||||
static createMappingArme(part, i) {
|
||||
return { column: `arme_${part}_${i}`, getter: (actor, context) => Mapping.getArme(actor, context, part, i) }
|
||||
}
|
||||
|
||||
static createMappingSort(part, i) {
|
||||
return { column: `sort_${part}_${i}`, getter: (actor, context) => Mapping.getSort(actor, context, part, i) }
|
||||
}
|
||||
}
|
||||
|
||||
const NB_ARMES = 10
|
||||
const NB_SORTS = 20
|
||||
const TABLEAU_ARMES = [...Array(NB_ARMES).keys()]
|
||||
const TABLEAU_SORTS = [...Array(NB_SORTS).keys()]
|
||||
|
||||
const MAPPING_BASE = [
|
||||
{ column: "ID", colName: 'ID', getter: (actor, context) => actor.id },
|
||||
{ column: "name", getter: (actor, context) => actor.name },
|
||||
{ column: "metier", colName: 'Métier', getter: (actor, context) => actor.system.metier },
|
||||
{ column: "biographie", colName: 'Biographie', getter: (actor, context) => actor.system.biographie },
|
||||
{ column: "taille", getter: (actor, context) => actor.system.carac.taille.value },
|
||||
{ column: "apparence", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.apparence.value },
|
||||
{ column: "constitution", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.constitution.value },
|
||||
{ column: "force", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.force.value },
|
||||
{ column: "agilite", rollClass: 'roll-carac', colName: 'Agilité', getter: (actor, context) => actor.system.carac.agilite.value },
|
||||
{ column: "dexterite", rollClass: 'roll-carac', colName: 'Dextérité', getter: (actor, context) => actor.system.carac.dexterite.value },
|
||||
{ column: "vue", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.vue.value },
|
||||
{ column: "ouie", rollClass: 'roll-carac', colName: 'Ouïe', getter: (actor, context) => actor.system.carac.ouie.value },
|
||||
{ column: "odoratgout", rollClass: 'roll-carac', colName: 'Odo-goût', getter: (actor, context) => actor.system.carac.odoratgout.value },
|
||||
{ column: "volonte", rollClass: 'roll-carac', colName: 'Volonté', getter: (actor, context) => actor.system.carac.volonte.value },
|
||||
{ column: "intellect", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.intellect.value },
|
||||
{ column: "empathie", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.empathie.value },
|
||||
{ column: "reve", rollClass: 'roll-carac', colName: 'Rêve', getter: (actor, context) => actor.system.carac.reve.value },
|
||||
{ column: "chance", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.chance.value },
|
||||
{ column: "melee", rollClass: 'roll-carac', colName: 'Mêlée', getter: (actor, context) => actor.system.carac.melee.value },
|
||||
{ column: "tir", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.tir.value },
|
||||
{ column: "lancer", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.lancer.value },
|
||||
{ column: "derobee", rollClass: 'roll-carac', colName: 'Dérobée', getter: (actor, context) => actor.system.carac.derobee.value },
|
||||
{ column: "vie", getter: (actor, context) => actor.system.sante.vie.max },
|
||||
{ column: "endurance", getter: (actor, context) => actor.system.sante.endurance.max },
|
||||
{ column: "plusdom", colName: '+dom', getter: (actor, context) => actor.getBonusDegat() },
|
||||
{ column: "protectionnaturelle", colName: 'Protection naturelle', getter: (actor, context) => actor.system.attributs.protection.value > 0 ? actor.system.attributs.protection.value : '' },
|
||||
{ column: "description", getter: (actor, context) => Mapping.getDescription(actor) },
|
||||
{ column: "armure", getter: (actor, context) => Mapping.getArmure(actor, context) },
|
||||
{ column: "protectionarmure", colName: 'Protection', getter: (actor, context) => Mapping.getProtectionArmure(actor, context) },
|
||||
{ column: "malus_armure", getter: (actor, context) => Mapping.getMalusArmure(actor, context) },
|
||||
{ column: "reve_actuel", rollClass: 'roll-reve-actuel', colName: 'Rêve actuel', getter: (actor, context) => actor.system.reve.reve.value },
|
||||
{ column: "chance_actuel", rollClass: 'roll-chance-actuelle', colName: 'Chance actuelle', getter: (actor, context) => actor.system.compteurs.chance.value },
|
||||
{ column: "vie_actuel", rollClass: 'jet-vie', getter: (actor, context) => actor.system.sante.vie.value },
|
||||
{ column: "endurance_actuel", rollClass: 'jet-endurance', getter: (actor, context) => actor.system.sante.endurance.value },
|
||||
{ column: "esquive", getter: (actor, context) => Mapping.getEsquive(context) },
|
||||
{ column: "esquive_armure", getter: (actor, context) => Mapping.getEsquiveArmure(context) },
|
||||
{ column: "competences", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_COMPETENCES) },
|
||||
{ column: "draconic", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_DRACONIC) },
|
||||
]
|
||||
|
||||
const MAPPING_ARMES = TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('name', i))
|
||||
.concat(TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('niveau', i)))
|
||||
.concat(TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('init', i)))
|
||||
.concat(TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('dommages', i)))
|
||||
const MAPPING_SORTS = TABLEAU_SORTS.map(i => ColumnMappingFactory.createMappingSort('voie', i))
|
||||
.concat(TABLEAU_SORTS.map(i => ColumnMappingFactory.createMappingSort('description', i)))
|
||||
.concat(TABLEAU_SORTS.map(i => ColumnMappingFactory.createMappingSort('bonus', i)))
|
||||
const MAPPING = MAPPING_BASE
|
||||
.concat(MAPPING_ARMES)
|
||||
.concat(MAPPING_SORTS)
|
||||
|
||||
export class Mapping {
|
||||
|
||||
static getMapping() {
|
||||
return MAPPING
|
||||
}
|
||||
|
||||
static getColumns() {
|
||||
return MAPPING.map(it => it.column)
|
||||
}
|
||||
|
||||
static getValues(actor) {
|
||||
const context = Mapping.prepareContext(actor)
|
||||
return MAPPING.map(it => it.getter(actor, context))
|
||||
}
|
||||
static getAsObject(actor) {
|
||||
const context = Mapping.prepareContext(actor)
|
||||
return Object.fromEntries(MAPPING.map(it => [it.column, {
|
||||
colName: it.colName ?? it.column,
|
||||
value: it.getter(actor, context)
|
||||
}]))
|
||||
}
|
||||
|
||||
static getValues(actor) {
|
||||
const context = Mapping.prepareContext(actor)
|
||||
return MAPPING.map(it => it.getter(actor, context))
|
||||
}
|
||||
|
||||
static prepareContext(actor) {
|
||||
return {
|
||||
armes: Mapping.prepareArmes(actor),
|
||||
armure: Mapping.prepareArmure(actor),
|
||||
esquive: Mapping.prepareEsquive(actor),
|
||||
sorts: Mapping.prepareSorts(actor)
|
||||
}
|
||||
}
|
||||
|
||||
static prepareArmes(actor) {
|
||||
const armes = actor.items.filter(it => it.type == ITEM_TYPES.arme)
|
||||
armes.push(RdDItemArme.corpsACorps(actor));
|
||||
armes.push(RdDItemArme.empoignade(actor));
|
||||
return armes.map(arme => [
|
||||
arme.system.unemain ? Mapping.prepareArme(actor, arme, 'unemain') : undefined,
|
||||
arme.system.deuxmains ? Mapping.prepareArme(actor, arme, 'deuxmains') : undefined,
|
||||
!(arme.system.unemain || arme.system.deuxmains) ? Mapping.prepareArme(actor, arme, 'competence') : undefined,
|
||||
arme.system.lancer != "" ? Mapping.prepareArme(actor, arme, 'lancer') : undefined,
|
||||
arme.system.tir != "" ? Mapping.prepareArme(actor, arme, 'tir') : undefined]
|
||||
.filter(it => it != undefined))
|
||||
.reduce((a, b) => a.concat(b), [])
|
||||
}
|
||||
|
||||
static prepareArme(actor, arme, maniement) {
|
||||
const nameCompetenceArme = RdDItemArme.getCompetenceArme(arme, maniement)
|
||||
const competence = actor.getCompetence(nameCompetenceArme)
|
||||
if (RdDItemCompetence.isNiveauBase(competence)) {
|
||||
return undefined
|
||||
}
|
||||
const categorie = Mapping.complementCategorie(arme, maniement)
|
||||
const dommages = Mapping.dommagesArme(actor, arme, maniement)
|
||||
return {
|
||||
name: arme.name + categorie,
|
||||
niveau: Misc.toSignedString(competence.system.niveau),
|
||||
init: Mapping.calculBaseInit(actor, competence.system.categorie) + competence.system.niveau,
|
||||
dommages: dommages,
|
||||
competence: competence,
|
||||
arme: arme
|
||||
}
|
||||
}
|
||||
static dommagesArme(actor, arme, maniement) {
|
||||
const dmgArme = RdDItemArme.dommagesReels(arme, maniement)
|
||||
const dommages = Misc.toSignedString(dmgArme + RdDBonus.bonusDmg(actor, maniement, dmgArme))
|
||||
switch (arme.system.mortalite) {
|
||||
case 'non-mortel': return `(${dommages})`
|
||||
case 'empoignade': return '-'
|
||||
}
|
||||
return dommages
|
||||
}
|
||||
|
||||
static complementCategorie(arme, maniement) {
|
||||
switch (maniement) {
|
||||
case 'unemain': return (arme.system.deuxmains) ? ' 1 main' : (arme.system.lancer || arme.system.tir) ? ' mêlée' : ''
|
||||
case 'deuxmains': return (arme.system.unemain) ? ' 2 mains' : (arme.system.lancer || arme.system.tir) ? ' mêlée' : ''
|
||||
case 'lancer': return (arme.system.unemain || arme.system.deuxmains || arme.system.tir) ? ' jet' : ''
|
||||
case 'tir': return (arme.system.unemain || arme.system.deuxmains || arme.system.lancer) ? ' tir' : ''
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
static calculBaseInit(actor, categorie) {
|
||||
const mapping = MAPPING_BASE.find(it => it.column == categorie)
|
||||
if (mapping) {
|
||||
switch (categorie) {
|
||||
case 'melee':
|
||||
case 'tir':
|
||||
case 'lancer':
|
||||
const caracteristique = Number(actor.system.carac[categorie].value)
|
||||
return Math.floor(caracteristique / 2)
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
static prepareArmure(actor) {
|
||||
const armures = actor.itemTypes[ITEM_TYPES.armure].filter(it => it.system.equipe)
|
||||
if (armures.length > 1) {
|
||||
console.warn(`${actor.name} a équipé ${armures.length} armures, seule la première sera considérée`)
|
||||
}
|
||||
if (armures.length > 0) {
|
||||
const armure = armures[0]
|
||||
return {
|
||||
name: armure.name,
|
||||
protection: armure.system.protection,
|
||||
malus: armure.system.malus ?? 0
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: '',
|
||||
protection: actor.system.attributs.protection.value,
|
||||
malus: 0
|
||||
}
|
||||
}
|
||||
|
||||
static prepareEsquive(actor) {
|
||||
const esquives = actor.getCompetences("Esquive")
|
||||
if (esquives.length > 0) {
|
||||
const esquive = esquives[0]
|
||||
return {
|
||||
name: esquive.name,
|
||||
niveau: esquive.system.niveau,
|
||||
competence: esquive
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
static prepareSorts(actor) {
|
||||
const codeVoies = Mapping.getCompetencesCategorie(actor, CATEGORIES_DRACONIC)
|
||||
.map(it => RdDItemSort.getCodeVoie(it.name))
|
||||
|
||||
return actor.itemTypes[ITEM_TYPES.sort].map(it => Mapping.prepareSort(it, codeVoies))
|
||||
.sort(Misc.ascending(it => `${it.voie} : ${it.description}`))
|
||||
}
|
||||
|
||||
static prepareSort(sort, voies) {
|
||||
return {
|
||||
voie: RdDItemSort.getCode(sort, voies),
|
||||
description: Mapping.descriptionSort(sort),
|
||||
bonus: Mapping.bonusCase(sort)
|
||||
}
|
||||
}
|
||||
|
||||
static descriptionSort(sort) {
|
||||
const ptSeuil = Array(sort.system.coutseuil).map(it => '*')
|
||||
const caseTMR = sort.system.caseTMRspeciale.length > 0 ? Mapping.toVar(sort.system.caseTMRspeciale) : Misc.upperFirst(TMRType[sort.system.caseTMR].name)
|
||||
const coutReve = 'r' + RdDItemSort.addSpaceToNonNumeric(sort.system.ptreve)
|
||||
const diff = 'R' + RdDItemSort.addSpaceToNonNumeric(sort.system.difficulte)
|
||||
return `${sort.name}${ptSeuil} (${caseTMR}) ${diff} ${coutReve}`
|
||||
}
|
||||
static toVar(caseSpeciale) {
|
||||
return Grammar.toLowerCaseNoAccent(caseSpeciale).startsWith('var') ? 'var' : caseSpeciale
|
||||
}
|
||||
|
||||
static bonusCase(sort) {
|
||||
const list = RdDItemSort.stringToBonuscases(sort.system.bonuscase).sort(Misc.descending(it => it.bonus))
|
||||
if (list.length > 0) {
|
||||
const bonus = list[0]
|
||||
return `+${bonus.bonus}% en ${bonus.case}`
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
static getDescription(actor) {
|
||||
const sexe = actor.system.sexe
|
||||
const sexeFeminin = sexe.length > 0 && sexe.charAt(0).toLowerCase() == 'f' ? 'Née' : 'Né'
|
||||
const race = ['', 'humain'].includes(Grammar.toLowerCaseNoAccent(actor.system.race)) ? '' : (actor.system.race + ' ')
|
||||
const heure = actor.system.heure
|
||||
const hn = `${sexeFeminin} à l'heure ${RdDTimestamp.definition(heure).avecArticle}`
|
||||
const age = (actor.system.age && actor.system.age >0) ? `${actor.system.age} ans` : undefined
|
||||
const taille = actor.system.taille
|
||||
const poids = actor.system.poids
|
||||
const cheveux = actor.system.cheveux ? `cheveux ${actor.system.cheveux}` : undefined
|
||||
const yeux = actor.system.yeux ? `yeux ${actor.system.yeux}` : undefined
|
||||
const beaute = actor.system.beaute ? `beauté ${actor.system.beaute}` : undefined
|
||||
const list = [race, hn, age, taille, poids, cheveux, yeux, beaute]
|
||||
return Misc.join(list.filter(it => it), ', ')
|
||||
}
|
||||
|
||||
static getArmure(actor, context) {
|
||||
return context.armure?.name ?? ''
|
||||
}
|
||||
|
||||
static getProtectionArmure(actor, context) {
|
||||
const naturelle = Number(actor.system.attributs.protection.value)
|
||||
if (context?.armure?.protection == undefined) {
|
||||
return naturelle
|
||||
}
|
||||
if (Number.isNumeric(context?.armure?.protection)) {
|
||||
return Number(context?.armure?.protection ?? 0) + naturelle
|
||||
}
|
||||
return context?.armure.protection + (naturelle > 0 ? `+${naturelle}` : '')
|
||||
}
|
||||
|
||||
static getMalusArmure(actor, context) {
|
||||
return context?.armure?.malus ?? 0
|
||||
}
|
||||
|
||||
static getEsquive(context) {
|
||||
if (context.esquive) {
|
||||
return Misc.toSignedString(context.esquive.niveau)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
static getEsquiveArmure(context) {
|
||||
if (context.esquive) {
|
||||
const niveau = context.esquive.niveau + context.armure.malus
|
||||
return Misc.toSignedString(niveau)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
static getCompetences(actor, categories) {
|
||||
const competences = Mapping.getCompetencesCategorie(actor, categories)
|
||||
if (competences.length == 0) {
|
||||
return ''
|
||||
}
|
||||
const byCategories = Mapping.competencesByCategoriesByNiveau(competences, categories)
|
||||
const txtByCategories = Object.values(byCategories)
|
||||
.map(it => it.competencesParNiveau)
|
||||
.map(byNiveau => {
|
||||
const niveaux = Object.keys(byNiveau)
|
||||
.map(it => Number(it)).sort(Misc.ascending())
|
||||
if (niveaux.length == 0) {
|
||||
return ''
|
||||
}
|
||||
const txtCategorieByNiveau = niveaux.map(niveau => {
|
||||
const names = Misc.join(byNiveau[niveau].map(it => it.name).sort(Misc.ascending()), ', ')
|
||||
return names + ' ' + Misc.toSignedString(niveau)
|
||||
})
|
||||
const txtCategorie = Misc.join(txtCategorieByNiveau, ' / ')
|
||||
return txtCategorie
|
||||
}).filter(it => it != '')
|
||||
|
||||
return Misc.join(txtByCategories, ' / ')
|
||||
}
|
||||
|
||||
static competencesByCategoriesByNiveau(competences, categories) {
|
||||
return categories.map(c => {
|
||||
return {
|
||||
categorie: c,
|
||||
competencesParNiveau: Misc.classify(
|
||||
competences.filter(comp => comp.system.categorie == c),
|
||||
comp => comp.system.niveau)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
static getArme(actor, context, part, numero) {
|
||||
if (numero < context.armes.length) {
|
||||
return context.armes[numero][part] ?? ''
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
static getCompetencesCategorie(actor, categories) {
|
||||
return actor.itemTypes[ITEM_TYPES.competence]
|
||||
.filter(it => categories.includes(it.system.categorie))
|
||||
.filter(it => !RdDItemCompetence.isNiveauBase(it))
|
||||
}
|
||||
|
||||
static getSort(actor, context, part, numero) {
|
||||
if (numero < context.sorts.length) {
|
||||
return context.sorts[numero][part]
|
||||
}
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
188
module/actor/random/app-personnage-aleatoire.js
Normal file
@ -0,0 +1,188 @@
|
||||
import { SHOW_DICE } from "../../constants.js";
|
||||
import { Misc } from "../../misc.js";
|
||||
import { RdDCarac } from "../../rdd-carac.js";
|
||||
import { RdDDice } from "../../rdd-dice.js";
|
||||
import { RdDNameGen } from "../../rdd-namegen.js";
|
||||
import { RdDTimestamp } from "../../time/rdd-timestamp.js";
|
||||
|
||||
const PATHS = [
|
||||
'name',
|
||||
'system.sexe',
|
||||
'system.age',
|
||||
'system.taille',
|
||||
'system.poids',
|
||||
'system.main',
|
||||
'system.heure',
|
||||
'system.cheveux',
|
||||
'system.yeux'
|
||||
]
|
||||
|
||||
const RANDOM_VALUES = {
|
||||
'system.sexe': { 'masculin': 1, 'féminin': 1 },
|
||||
'system.main': { 'droitier': 51, 'gaucher': 15, 'ambidextre': 6 },
|
||||
'system.cheveux': { 'noirs': 2, 'bruns': 5, 'châtains clair': 5, 'blonds': 4, 'blonds très clair': 1, 'roux carotte': 1, 'roux cuivré': 3 },
|
||||
'system.yeux': { 'noirs': 2, 'noisettes': 3, 'bruns vert': 4, 'verts': 3, 'bleus clair': 3, 'bleus gris': 2, 'gris': 1, 'mauves': 1, 'indigos': 1 },
|
||||
}
|
||||
|
||||
export class AppPersonnageAleatoire extends FormApplication {
|
||||
static preloadHandlebars() {
|
||||
loadTemplates([
|
||||
'systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs',
|
||||
])
|
||||
}
|
||||
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor/random/app-personnage-aleatoire.hbs",
|
||||
title: "Génération aléatoire",
|
||||
width: 'fit-content',
|
||||
height: 'fit-content',
|
||||
classes: ['app-personnage-aleatoire'],
|
||||
popOut: true,
|
||||
resizable: true
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
constructor(actor) {
|
||||
super({})
|
||||
this.actor = actor
|
||||
this.current = foundry.utils.duplicate(actor)
|
||||
this.checked = {
|
||||
'name': false,
|
||||
'system.sexe': true,
|
||||
'system.age': true,
|
||||
'system.taille': true,
|
||||
'system.poids': true,
|
||||
'system.main': true,
|
||||
'system.heure': true,
|
||||
'system.cheveux': true,
|
||||
'system.yeux': true
|
||||
}
|
||||
}
|
||||
|
||||
async getData(options) {
|
||||
return foundry.utils.mergeObject(await super.getData(options), {
|
||||
actor: this.actor,
|
||||
current: this.current,
|
||||
checked: this.checked,
|
||||
options: { isGM: game.user.isGM }
|
||||
})
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html)
|
||||
this.html = html
|
||||
this.html.find("button.button-cancel").click(async event => await this.close())
|
||||
this.html.find("button.button-apply").click(async event => await this.onApply())
|
||||
this.html.find("input.current-value").change(async event => await this.onChange(event))
|
||||
this.html.find("div.random-field[data-path='system.heure'] select.current-value").change(async event => await this.onChange(event))
|
||||
this.html.find("a.random").click(async event => await this.onRandom(event))
|
||||
this.html.find("a.reset").click(async event => await this.onReset(event))
|
||||
this.html.find("a.randomize-selected").click(async event => await this.onRandomizeSelected())
|
||||
this.html.find("input.check-for-random").click(async event => await this.onCheckForRandom(event))
|
||||
}
|
||||
async _updateObject(event, formData) { }
|
||||
|
||||
async onApply() {
|
||||
const updates = Object.fromEntries(
|
||||
PATHS.filter(path => game.user.isGM || path != 'name')
|
||||
.map(path => [path, this.current[path]])
|
||||
)
|
||||
await this.actor.update(updates)
|
||||
await this.close()
|
||||
}
|
||||
|
||||
getPath(selector) {
|
||||
const fields = this.html.find(selector).parents("div.random-field:first")
|
||||
return fields[0].attributes['data-path'].value
|
||||
}
|
||||
|
||||
async onChange(event) {
|
||||
const path = this.getPath(event.currentTarget)
|
||||
this.current[path] = event.currentTarget.value
|
||||
}
|
||||
|
||||
async onRandom(event) {
|
||||
const path = this.getPath(event.currentTarget)
|
||||
await this.setRandom(path);
|
||||
this.render()
|
||||
}
|
||||
|
||||
async onReset(event) {
|
||||
const path = this.getPath(event.currentTarget)
|
||||
this.current[path] = this.actor[path]
|
||||
await this.render()
|
||||
}
|
||||
|
||||
async onCheckForRandom(event) {
|
||||
const path = this.getPath(event.currentTarget)
|
||||
this.checked[path] = event.currentTarget.checked
|
||||
this.render()
|
||||
}
|
||||
|
||||
async onRandomizeSelected() {
|
||||
const paths = this.html.find("input.check-for-random:checked")
|
||||
.parents("div.random-field")
|
||||
.toArray()
|
||||
.map(it => it.attributes['data-path'].value)
|
||||
await Promise.all(paths.map(path => this.setRandom(path)))
|
||||
this.render()
|
||||
}
|
||||
|
||||
async setRandom(path) {
|
||||
this.current[path] = await this.random(path);
|
||||
}
|
||||
|
||||
async random(path) {
|
||||
switch (path) {
|
||||
case 'name':
|
||||
return await RdDNameGen.generate()
|
||||
case 'system.sexe':
|
||||
case 'system.main':
|
||||
case 'system.cheveux':
|
||||
case 'system.yeux':
|
||||
return await this.randomFromMap(RANDOM_VALUES[path])
|
||||
case 'system.poids':
|
||||
return await this.randomPoids()
|
||||
case 'system.taille':
|
||||
return await this.randomTaille()
|
||||
case 'system.age':
|
||||
return await RdDDice.rollTotal('(2d4kl)*10 + 1d7xo + 2d20kl')
|
||||
case 'system.heure':
|
||||
return RdDTimestamp.defHeure(await RdDDice.rollHeure({ rollMode: "selfroll", showDice: SHOW_DICE })).key
|
||||
}
|
||||
return 'unknown'
|
||||
}
|
||||
|
||||
async randomFromMap(valuesMap) {
|
||||
const max = Object.values(valuesMap).reduce(Misc.sum(), 0)
|
||||
const total = await RdDDice.rollTotal(`1d${max}`)
|
||||
let sum = 0
|
||||
for (let entry of Object.entries(valuesMap)) {
|
||||
sum = sum + entry[1]
|
||||
if (sum >= total) {
|
||||
return entry[0]
|
||||
}
|
||||
}
|
||||
return Object.keys(valuesMap)[0]
|
||||
}
|
||||
|
||||
async randomPoids() {
|
||||
const caracTaille = RdDCarac.getCaracDerivee(this.current.system.carac.taille.value)
|
||||
const range = caracTaille.poidsMax - caracTaille.poidsMin + 1
|
||||
const total = await RdDDice.rollTotal(`1d${range} + ${caracTaille.poidsMin}`)
|
||||
return total + ' kg'
|
||||
}
|
||||
|
||||
async randomTaille() {
|
||||
const caracTaille = RdDCarac.getCaracDerivee(this.current.system.carac.taille.value)
|
||||
const base = this.current.system.carac.taille.value * 2 + 60 + caracTaille.poidsMin
|
||||
const variation = Math.floor((caracTaille.poidsMax - caracTaille.poidsMin + base / 5) / 2)
|
||||
const total = await RdDDice.rollTotal(`2d${variation} + ${base}`)
|
||||
const cm = total % 100
|
||||
const m = (total - cm) / 100
|
||||
return `${m}m${cm}`
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,21 +1,31 @@
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { RdDActorSheet } from "./actor-sheet.js";
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
import { RdDBaseActorSheet } from "./base-actor-sheet.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDActorVehiculeSheet extends RdDActorSheet {
|
||||
export class RdDActorVehiculeSheet extends RdDBaseActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
RdDUtility.initAfficheContenu();
|
||||
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["rdd", "sheet", "actor"],
|
||||
return foundry.utils.mergeObject(RdDBaseActorSheet.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor-vehicule-sheet.html",
|
||||
width: 640,
|
||||
height: 720,
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
|
||||
});
|
||||
width: 640, height: 720,
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
let formData = await super.getData();
|
||||
foundry.utils.mergeObject(formData,
|
||||
{
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
effects: this.actor.effects.map(e => foundry.utils.deepClone(e)),
|
||||
limited: this.actor.limited,
|
||||
owner: this.actor.isOwner,
|
||||
});
|
||||
|
||||
this.timerRecherche = undefined;
|
||||
return formData;
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
28
module/actor/vehicule.js
Normal file
@ -0,0 +1,28 @@
|
||||
import { RdDBaseActor } from "./base-actor.js";
|
||||
|
||||
export class RdDVehicule extends RdDBaseActor {
|
||||
|
||||
static get defaultIcon() {
|
||||
return "systems/foundryvtt-reve-de-dragon/icons/vehicules/charette.webp";
|
||||
}
|
||||
isVehicule() { return true }
|
||||
|
||||
canReceive(item) {
|
||||
return item.isInventaire();
|
||||
}
|
||||
|
||||
getEncombrementMax() {
|
||||
return this.system.capacite_encombrement;
|
||||
}
|
||||
|
||||
async vehicleIncDec(name, inc) {
|
||||
if (!['resistance', 'structure'].includes(name)) {
|
||||
return
|
||||
}
|
||||
const newValue = this.system.etat[name].value + inc;
|
||||
if (0 <= newValue && newValue <= this.system.etat[name].max) {
|
||||
await this.update({ [`system.etat.${name}.value`]: newValue })
|
||||
}
|
||||
}
|
||||
|
||||
}
|
706
module/apps/rdd-import-stats.js
Normal file
@ -0,0 +1,706 @@
|
||||
/************************************************************************************/
|
||||
import "./xregexp-all.js";
|
||||
import { SystemCompendiums } from "../settings/system-compendiums.js";
|
||||
import { RdDBaseActorReve } from "../actor/base-actor-reve.js";
|
||||
import { Grammar } from "../grammar.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { ENTITE_INCARNE, ENTITE_NONINCARNE } from "../constants.js";
|
||||
import { RdDItemTete } from "../item/tete.js";
|
||||
import { ITEM_TYPES } from "../constants.js";
|
||||
|
||||
const WHITESPACES = "\\s+"
|
||||
const NUMERIC = "[\\+\\-]?\\d+"
|
||||
const NUMERIC_VALUE = "(?<value>" + NUMERIC + ")"
|
||||
|
||||
const XREGEXP_COMP_CREATURE = WHITESPACES + "(?<carac>\\d+)"
|
||||
+ WHITESPACES + NUMERIC_VALUE
|
||||
+ "(" + WHITESPACES + "(?<init>\\d+)?\\s+?(?<dommages>[\\+\\-]?\\d+)?" + ")?"
|
||||
|
||||
// Skill parser depending on the type of actor
|
||||
const compParser = {
|
||||
personnage: "(\\s+\\((?<special>[^\\)]+)\\))?(,\\s*\\p{Letter}+)*(\\s+(?<malus>avec armure))?" + WHITESPACES + NUMERIC_VALUE,
|
||||
creature: XREGEXP_COMP_CREATURE,
|
||||
entite: XREGEXP_COMP_CREATURE
|
||||
}
|
||||
|
||||
const MANIEMENTS = {
|
||||
'de lancer': (weapon) => { return { name: weapon.system.lancer, categorie: 'lancer' } },
|
||||
'de jet': (weapon) => { return { name: weapon.system.lancer, categorie: 'lancer' } },
|
||||
'à une main': (weapon) => { return { name: weapon.system.competence, categorie: 'melee' } },
|
||||
'à deux mains': (weapon) => { return { name: weapon.system.competence.replace("à 1 main", "à 2 mains"), categorie: 'melee' } },
|
||||
'mêlée': (weapon) => { return { name: weapon.system.competence, categorie: 'melee' } },
|
||||
}
|
||||
const XREGEXP_WEAPON_MANIEMENT = "(?<maniement>(" + Misc.join(Object.keys(MANIEMENTS), '|') + "))"
|
||||
|
||||
const XREGEXP_SORT_VOIE = "(?<voies>[OHNT](\\/[OHNT])*)"
|
||||
const XREGEXP_SORT_NAME = "(?<name>[^\\(]+)"
|
||||
const XREGEXP_SORT_CASE = "(?<coord>([A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+|[A-M]\\d{1,2}))"
|
||||
|
||||
const XREGEXP_SORT = "(" + XREGEXP_SORT_VOIE
|
||||
+ WHITESPACES + XREGEXP_SORT_NAME
|
||||
+ WHITESPACES + "\\(" + XREGEXP_SORT_CASE + "\\)"
|
||||
+ WHITESPACES + "R(?<diff>([\\-\\d]+|(\\w|\\s)+))"
|
||||
+ WHITESPACES + "r(?<reve>(\\d+(\\+)?|\\s\\w+))"
|
||||
+ "(" + WHITESPACES + "\\+(?<bonus>\\d+)\\s?%" + WHITESPACES + "en" + WHITESPACES + "(?<bonuscase>[A-M]\\d{1,2})" + ")?"
|
||||
+ ")"
|
||||
|
||||
const XREGEXP_SORTRESERVE_CASE = "(?<coord>[A-M]\\d{1,2})";
|
||||
|
||||
const XREGEXP_SORT_RESERVE = XREGEXP_SORTRESERVE_CASE
|
||||
+ WHITESPACES + XREGEXP_SORT_NAME
|
||||
+ WHITESPACES + "(\\((?<description>[^\\)]+)\\))?"
|
||||
|
||||
// Main class for parsing a stat block
|
||||
export class RdDStatBlockParser {
|
||||
|
||||
static openInputDialog() {
|
||||
let dialog = new Dialog({
|
||||
title: "Import de stats de PNJ/Créatures",
|
||||
content: `
|
||||
<div>
|
||||
<p>Coller le texte de la stat ici</p>
|
||||
<textarea id="statBlock" style="width: 100%; height: 200px;"></textarea>
|
||||
</div>
|
||||
`,
|
||||
buttons: {
|
||||
ok: {
|
||||
label: "OK",
|
||||
callback: async (html) => {
|
||||
let statBlock = html.find("#statBlock")[0].value;
|
||||
await RdDStatBlockParser.parseStatBlock(statBlock);
|
||||
dialog.close();
|
||||
}
|
||||
},
|
||||
cancel: {
|
||||
label: "Cancel"
|
||||
}
|
||||
}
|
||||
});
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
static fixWeirdPDF(statString) {
|
||||
// Split the statString into lines
|
||||
let lines = statString.split("\n");
|
||||
let newLines = [];
|
||||
let index = 0;
|
||||
let nextType = "string";
|
||||
// Loop through each line
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
// remove trailing spaces
|
||||
lines[i] = lines[i].trim();
|
||||
// Is it text ?
|
||||
if (lines[i].match(/^[a-zA-Zéêè\s]+/)) {
|
||||
if (nextType == "string") {
|
||||
newLines[index] = lines[i];
|
||||
nextType = "number";
|
||||
} else {
|
||||
console.log("Wrong sequence string detected...", lines[i], nextType);
|
||||
}
|
||||
}
|
||||
// Is it a number ?
|
||||
if (lines[i].match(/^[\d\s]+/)) {
|
||||
if (nextType == "number") {
|
||||
newLines[index] = newLines[index] + lines[i];
|
||||
nextType = "string";
|
||||
index++;
|
||||
} else {
|
||||
console.log("Wrong sequence number detected...", lines[i], nextType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static getHeureKey(heure) {
|
||||
for (let h of game.system.rdd.config.heuresRdD) {
|
||||
if (h.label.toLowerCase() == heure.toLowerCase()) {
|
||||
return h.value;
|
||||
}
|
||||
}
|
||||
return "vaisseau";
|
||||
}
|
||||
|
||||
static fixCompName(name) {
|
||||
name = name.replace("Voie d'", "");
|
||||
name = name.replace("Voie de ", "");
|
||||
return name
|
||||
}
|
||||
|
||||
static async parseStatBlock(statString) {
|
||||
|
||||
//statString = statBlock03;
|
||||
if (!statString) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Special function to fix strange/weird copy/paste from PDF readers
|
||||
// Unused up to now : this.fixWeirdPDF(statString);
|
||||
|
||||
// Replace all endline by space in the statString
|
||||
statString = statString.replace(/\n/g, " ");
|
||||
// Remove all multiple spaces
|
||||
statString = statString.replace(/\s{2,}/g, " ");
|
||||
// Remove all leading and trailing spaces
|
||||
statString = statString.trim();
|
||||
|
||||
// TODO: check for entite
|
||||
let type = RdDStatBlockParser.parseActorType(statString);
|
||||
|
||||
// Now start carac
|
||||
let actorData = foundry.utils.deepClone(game.model.Actor[type]);
|
||||
let items = [];
|
||||
|
||||
actorData.flags = { hautRevant: false, malusArmure: 0, type }
|
||||
for (let key in actorData.carac) {
|
||||
let caracDef = actorData.carac[key];
|
||||
// Parse the stat string for each caracteristic
|
||||
let carac = XRegExp.exec(statString, XRegExp(caracDef.label + "\\s+(?<value>\\d+)", 'giu'));
|
||||
if (carac?.value) {
|
||||
actorData.carac[key].value = Number(carac.value);
|
||||
}
|
||||
}
|
||||
|
||||
// If creature we need to setup additionnal fields
|
||||
switch (type) {
|
||||
case "creature":
|
||||
RdDStatBlockParser.parseCreature(statString, actorData)
|
||||
await RdDStatBlockParser.parseCompetences(statString, actorData, items)
|
||||
break
|
||||
case "entite":
|
||||
RdDStatBlockParser.parseEntite(statString, actorData)
|
||||
await RdDStatBlockParser.parseCompetences(statString, actorData, items)
|
||||
break
|
||||
case "personnage":
|
||||
await RdDStatBlockParser.parseArmors(statString, actorData, items);
|
||||
await RdDStatBlockParser.parseCompetences(statString, actorData, items);
|
||||
await RdDStatBlockParser.parseWeapons(statString, items);
|
||||
await RdDStatBlockParser.parseHautReve(statString, actorData, items);
|
||||
RdDStatBlockParser.parsePersonnage(statString, actorData);
|
||||
}
|
||||
|
||||
const name = RdDStatBlockParser.extractName(type, statString);
|
||||
|
||||
actorData.flags = undefined
|
||||
console.log(actorData);
|
||||
|
||||
let newActor = await RdDBaseActorReve.create({ name, type, system: actorData, items });
|
||||
await newActor.remiseANeuf()
|
||||
await RdDStatBlockParser.adjustAttacks(newActor)
|
||||
await RdDStatBlockParser.setValeursActuelles(newActor, statString)
|
||||
await newActor?.sheet.render(true)
|
||||
}
|
||||
|
||||
static async parseCompetences(statString, actorData, items) {
|
||||
const competences = await SystemCompendiums.getCompetences(actorData.flags.type);
|
||||
//console.log("Competences : ", competences);
|
||||
for (let competence of competences) {
|
||||
let pushed = actorData.flags.type != "personnage"
|
||||
let compNameToSearch = RdDStatBlockParser.fixCompName(competence.name)
|
||||
XRegExp.forEach(statString, XRegExp("\\s" + compNameToSearch + compParser[actorData.flags.type], 'giu'),
|
||||
function (compMatch, i) {
|
||||
items.push(RdDStatBlockParser.prepareCompetence(actorData, competence, compMatch))
|
||||
if (!compMatch.special) {
|
||||
pushed = true
|
||||
}
|
||||
})
|
||||
if (!pushed) {
|
||||
// ajout niveau de base
|
||||
items.push(competence.toObject())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static prepareCompetence(actorData, competence, compMatch) {
|
||||
const comp = competence.toObject();
|
||||
if (compMatch.special) {
|
||||
comp._id = undefined
|
||||
comp.name = `${comp.name} (${compMatch.special})`
|
||||
}
|
||||
comp.system.niveau = Number(compMatch.value);
|
||||
if (compMatch.malus) {
|
||||
comp.system.niveau = Number(compMatch.value) - actorData.flags.malusArmure
|
||||
}
|
||||
if (comp.system.categorie == 'draconic' && comp.system.niveau > -11) {
|
||||
actorData.flags.hautRevant = true
|
||||
}
|
||||
if (["creature", "entite"].includes(actorData.flags.type)) {
|
||||
comp.system.carac_value = Number(compMatch.carac);
|
||||
if (compMatch.dommages != undefined) {
|
||||
comp.system.dommages = Number(compMatch.dommages)
|
||||
comp.system.iscombat = true
|
||||
}
|
||||
}
|
||||
return comp
|
||||
}
|
||||
|
||||
static async parseArmors(statString, actorData, items) {
|
||||
const armors = await SystemCompendiums.getWorldOrCompendiumItems("armure", "equipement");
|
||||
for (let armor of armors) {
|
||||
let matchArmor = XRegExp.exec(statString, XRegExp(armor.name, 'giu'));
|
||||
if (matchArmor) {
|
||||
armor = armor.toObject()
|
||||
armor.system.equipe = true
|
||||
actorData.flags.malusArmure = armor.system.malus
|
||||
items.push(armor)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static async parseWeapons(statString, items) {
|
||||
const weapons = await SystemCompendiums.getWorldOrCompendiumItems("arme", "equipement");
|
||||
//console.log("Equipement : ", equipment);
|
||||
// TODO: les noms d'armes peuvent avoir un suffixe (à une main, lancée) qui détermine la compétence correspondante
|
||||
// TODO: une arme peut être spécifique ("fourche"), ajouter une compétence dans ces cas là?
|
||||
for (let weapon of weapons) {
|
||||
let nomArmeManiement = XRegExp.exec(weapon.name, XRegExp(".*" + XREGEXP_WEAPON_MANIEMENT));
|
||||
if (nomArmeManiement) {
|
||||
continue // ignore les objets 'Dague de jet" ou "dague mêlée"
|
||||
}
|
||||
let weapMatch = XRegExp.exec(statString, XRegExp(weapon.name
|
||||
+ "(\\s*" + XREGEXP_WEAPON_MANIEMENT + ")?"
|
||||
+ "\\s+(?<value>[\\+\\-]?\\d+)", 'giu'));
|
||||
if (weapMatch) {
|
||||
weapon = weapon.toObject();
|
||||
weapon.system.equipe = 'true';
|
||||
items.push(weapon);
|
||||
|
||||
const niveau = Number(weapMatch.value);
|
||||
// now process the skill
|
||||
if (weapMatch?.maniement) {
|
||||
RdDStatBlockParser.setNiveauCompetenceArme(items, MANIEMENTS[weapMatch.maniement](weapon), niveau)
|
||||
}
|
||||
else {
|
||||
RdDStatBlockParser.setNiveauCompetenceArme(items, { name: weapon.system.competence, categorie: 'melee' }, niveau)
|
||||
RdDStatBlockParser.setNiveauCompetenceArme(items, { name: weapon.system.tir, categorie: 'tir' }, niveau)
|
||||
RdDStatBlockParser.setNiveauCompetenceArme(items, { name: weapon.system.lancer, categorie: 'lancer' }, niveau)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static setNiveauCompetenceArme(items, competence, niveau) {
|
||||
if (competence != "") {
|
||||
const item = items.find(i => i.system.categorie == competence.categorie && Grammar.equalsInsensitive(i.name, competence.name))
|
||||
if (item) {
|
||||
item.system.niveau = niveau
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static async adjustAttacks(newActor) {
|
||||
if (["creature", "entite"].includes(newActor.type)) {
|
||||
const bonusDommages = newActor.getBonusDegat()
|
||||
const ajustementAttaques = newActor.itemTypes[ITEM_TYPES.competencecreature].filter(it => it.system.iscombat)
|
||||
.map(it => {
|
||||
return {
|
||||
_id: it.id,
|
||||
'system.categorie': 'melee',
|
||||
'system.dommages': it.system.dommages - bonusDommages
|
||||
}
|
||||
})
|
||||
await newActor.updateEmbeddedDocuments('Item', ajustementAttaques)
|
||||
}
|
||||
}
|
||||
|
||||
static async setValeursActuelles(newActor, statString) {
|
||||
const updates = {
|
||||
}
|
||||
const endurance = XRegExp.exec(statString, XRegExp("endurance\\s+(?<value>\\d+)\\s+(\\(actuelle\\s*:\\s+(?<actuelle>\\d+)\\))?", 'giu'));
|
||||
if (endurance?.value) {
|
||||
if (newActor.getEnduranceMax() != endurance.value) {
|
||||
ui.notifications.warn(`Vérifier le calcul de l'endurance, calcul: ${newActor.getEnduranceMax()} / import: ${endurance.value}`)
|
||||
}
|
||||
}
|
||||
if (endurance?.actuelle) {
|
||||
updates['system.sante.endurance.value'] = Number(endurance?.actuelle)
|
||||
}
|
||||
|
||||
const vie = XRegExp.exec(statString, XRegExp("vie\\s+(?<value>\\d+)\\s+(\\(actuelle\\s*:\\s+(?<actuelle>\\d+)\\))?", 'giu'));
|
||||
if (vie?.value) {
|
||||
if (newActor.getVieMax() != vie.value) {
|
||||
ui.notifications.warn(`Vérifier le calcul de la vie, calcul: ${newActor.getVieMax()} / import: ${vie.value}`)
|
||||
}
|
||||
}
|
||||
if (vie?.actuelle) {
|
||||
updates['system.sante.vie.value'] = Number(vie?.actuelle)
|
||||
}
|
||||
await newActor.update(updates)
|
||||
}
|
||||
|
||||
static async parseHautReve(statString, actorData, items) {
|
||||
// Attemp to detect spell
|
||||
let sorts = await SystemCompendiums.getWorldOrCompendiumItems("sort", "sorts-oniros");
|
||||
sorts = sorts.concat(await SystemCompendiums.getWorldOrCompendiumItems("sort", "sorts-hypnos"));
|
||||
sorts = sorts.concat(await SystemCompendiums.getWorldOrCompendiumItems("sort", "sorts-narcos"));
|
||||
sorts = sorts.concat(await SystemCompendiums.getWorldOrCompendiumItems("sort", "sorts-thanatos"));
|
||||
|
||||
XRegExp.forEach(statString, XRegExp(XREGEXP_SORT, 'gu' /* keep case sensitive to match the spell draconic skill */),
|
||||
function (matchSort, i) {
|
||||
actorData.flags.hautRevant = true
|
||||
const sortName = Grammar.toLowerCaseNoAccent(matchSort.name).trim().replace("’", "'");
|
||||
let sort = sorts.find(s => Grammar.toLowerCaseNoAccent(s.name) == sortName)
|
||||
if (sort) {
|
||||
sort = sort.toObject();
|
||||
if (matchSort.bonus && matchSort.bonuscase) {
|
||||
sort.system.bonuscase = `${matchSort.bonuscase}:${matchSort.bonus}`;
|
||||
}
|
||||
items.push(sort);
|
||||
}
|
||||
else {
|
||||
ui.notifications.warn(`Impossible de trouver le sort ${matchSort.name} / ${sortName}`)
|
||||
}
|
||||
})
|
||||
const sortsReserve = XRegExp.exec(statString, XRegExp('En réserve\\s+(?<reserve>.*)', 'gu' /* keep case sensitive to match the spell draconic skill */))
|
||||
if (sortsReserve?.reserve) {
|
||||
actorData.flags.hautRevant = true
|
||||
XRegExp.forEach(sortsReserve.reserve, XRegExp(XREGEXP_SORT_RESERVE, 'giu'),
|
||||
function (matchSortReserve, i) {
|
||||
const name = Grammar.toLowerCaseNoAccent(matchSortReserve.name).trim().replace("’", "'");
|
||||
const sort = sorts.find(s => Grammar.toLowerCaseNoAccent(s.name) == name)
|
||||
if (sort) {
|
||||
if (!items.find(it => it._id == sort.id)) {
|
||||
const nouveauSort = sort.toObject()
|
||||
nouveauSort.system.bonuscase = `${matchSortReserve.coord}:1`;
|
||||
items.push(sort.toObject())
|
||||
}
|
||||
items.push({
|
||||
name: sort.name,
|
||||
type: 'sortreserve',
|
||||
img: sort.img,
|
||||
system: {
|
||||
sortid: sort.id,
|
||||
draconic: sort.system.draconic,
|
||||
coord: matchSortReserve.coord,
|
||||
ptreve: Number(sort.system.ptreve.match(/\d+/)),
|
||||
},
|
||||
description: matchSortReserve.description
|
||||
})
|
||||
}
|
||||
else {
|
||||
ui.notifications.warn(`Impossible de mettre ${matchSortReserve.name} en réserve en ${matchSortReserve.coord}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (actorData.flags.hautRevant) {
|
||||
const donHR = await RdDItemTete.teteDonDeHautReve();
|
||||
if (donHR) {
|
||||
items.push(donHR.toObject());
|
||||
}
|
||||
|
||||
const demiReve = XRegExp.exec(statString, XRegExp("Demi-rêve\\s+(?<value>[A-M]\\d{1,2})", 'giu'))
|
||||
actorData.reve.tmrpos.coord = demiReve?.value ?? 'A1'
|
||||
}
|
||||
}
|
||||
|
||||
static parsePersonnage(statString, actorData) {
|
||||
actorData.reve.seuil.value = actorData.carac.reve.value
|
||||
actorData.compteurs.chance.value = actorData.carac.chance.value
|
||||
|
||||
const reveActuel = XRegExp.exec(statString, XRegExp("Rêve actuel\\s+(?<value>\\d+)", 'giu'))
|
||||
actorData.reve.reve.value = reveActuel?.value ? Number(reveActuel.value) : actorData.reve.seuil.value
|
||||
|
||||
const feminin = XRegExp.exec(statString, XRegExp("né(?<value>e?) à", 'giu'));
|
||||
actorData.sexe = (feminin?.value == 'e') ? 'féminin' : 'masculin';
|
||||
|
||||
// Get hour name : heure du XXXXX
|
||||
const heure = XRegExp.exec(statString, XRegExp("heure (du|de la|des|de l\')\\s*(?<value>[A-Za-zÀ-ÖØ-öø-ÿ\\s]+),", 'giu'));
|
||||
actorData.heure = this.getHeureKey(heure?.value || "Vaisseau");
|
||||
|
||||
// Get age
|
||||
const age = XRegExp.exec(statString, XRegExp("(?<value>\\d+) ans", 'giu'));
|
||||
if (age?.value) {
|
||||
actorData.age = Number(age.value);
|
||||
}
|
||||
// Get height
|
||||
const taille = XRegExp.exec(statString, XRegExp("(?<value>\\d+m\\d+)", 'giu'));
|
||||
if (taille?.value) {
|
||||
actorData.taille = taille.value;
|
||||
}
|
||||
// Get weight
|
||||
const poids = XRegExp.exec(statString, XRegExp(",\\s+(?<value>\\d+)\\s+kg", 'giu'));
|
||||
if (poids?.value) {
|
||||
actorData.poids = poids.value + ' kg';
|
||||
}
|
||||
// Get cheveux
|
||||
const cheveux = XRegExp.exec(statString, XRegExp("kg,\\s+(?<value>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+),\\s+yeux", 'giu'));
|
||||
if (cheveux?.value) {
|
||||
actorData.cheveux = cheveux.value;
|
||||
}
|
||||
// Get yeux
|
||||
const yeux = XRegExp.exec(statString, XRegExp("yeux\\s+(?<value>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+), Beau", 'giu'));
|
||||
if (yeux?.value) {
|
||||
actorData.yeux = yeux.value;
|
||||
}
|
||||
|
||||
// Get beauty
|
||||
const beaute = XRegExp.exec(statString, XRegExp("beauté\\s+(?<value>\\d+)", 'giu'));
|
||||
if (beaute?.value) {
|
||||
actorData.beaute = Number(beaute.value);
|
||||
}
|
||||
}
|
||||
|
||||
static parseCreature(statString, actorData) {
|
||||
let protection = XRegExp.exec(statString, XRegExp("protection(\\s+naturelle)?\\s+(?<value>[\\-]?\\d+)", 'giu'));
|
||||
if (protection?.value) {
|
||||
actorData.attributs.protection.value = Number(protection.value);
|
||||
}
|
||||
let vitesse = XRegExp.exec(statString, XRegExp("vitesse\\s+(?<value>[\\d\\/]+)", 'giu'));
|
||||
if (vitesse?.value) {
|
||||
actorData.attributs.vitesse.value = vitesse.value;
|
||||
}
|
||||
}
|
||||
|
||||
static parseEntite(statString, actorData) {
|
||||
actorData.definition.categorieentite = 'cauchemar'
|
||||
actorData.definition.typeentite = ENTITE_NONINCARNE
|
||||
let endurance = XRegExp.exec(statString, XRegExp("endurance\\s+(?<value>\\d+)", 'giu'));
|
||||
if (endurance?.value) {
|
||||
actorData.sante.endurance.value = Number(endurance.value);
|
||||
actorData.sante.endurance.max = Number(endurance.value);
|
||||
actorData.definition.typeentite = ENTITE_INCARNE
|
||||
}
|
||||
let vitesse = XRegExp.exec(statString, XRegExp("vitesse\\s+(?<value>[\\d\\/]+)", 'giu'));
|
||||
if (vitesse?.value) {
|
||||
actorData.attributs.vitesse.value = vitesse.value;
|
||||
}
|
||||
}
|
||||
|
||||
static parseActorType(statString) {
|
||||
let force = XRegExp.exec(statString, XRegExp("Force\\s+(?<value>[\\+\\-]?\\d+)", 'giu'))
|
||||
let vue = XRegExp.exec(statString, XRegExp("Vue\\s+(?<value>[\\+\\-]?\\d+)", 'giu'))
|
||||
let perception = XRegExp.exec(statString, XRegExp("perception\\s+(?<value>\\d+)", 'giu'))
|
||||
if (!force) {
|
||||
return "entite"
|
||||
}
|
||||
if (!vue || perception) {
|
||||
return "creature"
|
||||
}
|
||||
return "personnage"
|
||||
}
|
||||
|
||||
static extractName(actorType, statString) {
|
||||
if (actorType == "personnage") {
|
||||
// Check if ',né le' is present
|
||||
let namePersonnage = "Importé"
|
||||
if (statString.includes(", né")) {
|
||||
// Name is all string before first comma ','
|
||||
namePersonnage = XRegExp.exec(statString, XRegExp("(?<value>[\\p{Letter}\'\\-\\s\\d]+),", 'giu'));
|
||||
} else {
|
||||
namePersonnage = XRegExp.exec(statString, XRegExp("(?<value>[\\p{Letter}\'\\-\\s\\d]+)\\s+TAILLE", 'giu'));
|
||||
}
|
||||
if (namePersonnage?.value) {
|
||||
return Misc.upperFirst(namePersonnage?.value.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
const name = XRegExp.exec(statString, XRegExp("(?<value>.+)\\s+taille", 'giu'));
|
||||
if (actorType == "entite") {
|
||||
if (!(name?.value)) {
|
||||
const nameEntiteReve = XRegExp.exec(statString, XRegExp("(?<value>.+)\\s+rêve", 'giu'));
|
||||
return Misc.upperFirst(nameEntiteReve?.value || "Importé");
|
||||
}
|
||||
}
|
||||
return Misc.upperFirst(name?.value || "Importé");
|
||||
}
|
||||
|
||||
static warning(message) {
|
||||
ui.notifications.warn(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/************************************************************************************/
|
||||
// Some internal test strings
|
||||
let statBlock01 = `+$16(/, baron de Sylvedire, né à l’heure du
|
||||
Roseau, 40 ans, 1m78, 65 kg, Beauté 13.
|
||||
TAILLE
|
||||
10
|
||||
Mêlée
|
||||
14
|
||||
APPARENCE
|
||||
13
|
||||
Tir
|
||||
11
|
||||
CONSTITUTION
|
||||
12
|
||||
Lancer
|
||||
11
|
||||
FORCE
|
||||
12
|
||||
Dérobée
|
||||
13
|
||||
AGILITÉ
|
||||
16
|
||||
Vie
|
||||
11
|
||||
DEXTÉRITÉ
|
||||
13
|
||||
Endurance
|
||||
25
|
||||
VUE
|
||||
10
|
||||
+dom
|
||||
0
|
||||
OUÏE
|
||||
11
|
||||
Protection
|
||||
2 ou 4
|
||||
ODO-GOÛT
|
||||
9
|
||||
cuir souple
|
||||
VOLONTÉ
|
||||
14
|
||||
ou cuir / métal
|
||||
INTELLECT
|
||||
9
|
||||
EMPATHIE
|
||||
11
|
||||
RÊVE
|
||||
13
|
||||
CHANCE
|
||||
10
|
||||
niv
|
||||
init
|
||||
+dom
|
||||
Épée dragonne
|
||||
+5
|
||||
12
|
||||
+3
|
||||
Hache de bataille
|
||||
+6
|
||||
13
|
||||
+3
|
||||
Bouclier moyen
|
||||
+5
|
||||
Dague mêlée
|
||||
+4
|
||||
11
|
||||
+1
|
||||
Corps à corps
|
||||
+4
|
||||
11
|
||||
(0)
|
||||
Esquive
|
||||
+8
|
||||
Escalade, Saut +4 / Commerce +3 / Équitation
|
||||
+6 / Chirurgie 0 / Survie en extérieur +4 / Survie fo-
|
||||
rêt +6 / Acrobatie -2 / Métallurgie +2 / Natation +3 /
|
||||
Légendes -1 / Écriture -4
|
||||
`;
|
||||
|
||||
let statBlock02 = `/HVJDUGHV
|
||||
TAILLE
|
||||
11
|
||||
Mêlée
|
||||
12
|
||||
CONSTITUTION
|
||||
11
|
||||
Tir
|
||||
11
|
||||
FORCE
|
||||
12
|
||||
Lancer
|
||||
11
|
||||
AGILITÉ
|
||||
12
|
||||
Dérobée
|
||||
11
|
||||
DEXTERITÉ
|
||||
11
|
||||
Vie
|
||||
11
|
||||
VUE
|
||||
11
|
||||
Endurance
|
||||
22
|
||||
OUÏE
|
||||
11
|
||||
Vitesse
|
||||
12
|
||||
VOLONTÉ
|
||||
10
|
||||
+dom
|
||||
0
|
||||
Protection
|
||||
4
|
||||
cuir / métal
|
||||
niv
|
||||
init
|
||||
+dom
|
||||
Hache de bataille
|
||||
+4
|
||||
10
|
||||
+3
|
||||
Bouclier moyen
|
||||
+4
|
||||
Dague mêlée
|
||||
+3
|
||||
9
|
||||
+1
|
||||
Arc
|
||||
+5
|
||||
10
|
||||
+2
|
||||
Corps à corps
|
||||
+3
|
||||
9
|
||||
(0)
|
||||
Esquive avec armure
|
||||
+2
|
||||
Course +1/ Vigilance +4
|
||||
`;
|
||||
|
||||
let statBlock03 = `rencontres sont laissées à /HVFKLHQVORXSVGXEDURQ
|
||||
chaque gardien des rêves.
|
||||
TAILLE
|
||||
8
|
||||
Vie
|
||||
10
|
||||
CONSTITUTION FORCE
|
||||
12
|
||||
11
|
||||
Endurance
|
||||
Vitesse
|
||||
12/38
|
||||
21
|
||||
/HVFKLHQV]RPELV
|
||||
PERCEPTION 13
|
||||
+dom
|
||||
0
|
||||
VOLONTÉ
|
||||
10
|
||||
Protection
|
||||
0
|
||||
Les « monstres » apparaîtront un soir, durant
|
||||
RÊVE
|
||||
10
|
||||
l’heure du Serpent, et attaqueront les voya-
|
||||
niv
|
||||
init
|
||||
+dom
|
||||
geurs à leur campement. Si ces derniers ne
|
||||
Morsure
|
||||
13
|
||||
+4
|
||||
10
|
||||
+1
|
||||
campent pas, ils apparaîtront tout de même à
|
||||
Esquive
|
||||
11
|
||||
+3
|
||||
l’heure du Serpent. Le feu ne les effraie pas. Ils
|
||||
Course, Saut
|
||||
12
|
||||
+3
|
||||
ne sont pas très rapides, mais en revanche, très
|
||||
Discrétion
|
||||
12
|
||||
+3
|
||||
silencieux : ils n’aboient pas. Les voyageurs
|
||||
Vigilance
|
||||
13
|
||||
+3
|
||||
`
|
78
module/apps/rdd-text-roll-editor.js
Normal file
@ -0,0 +1,78 @@
|
||||
import "./xregexp-all.js";
|
||||
import { SystemCompendiums } from "../settings/system-compendiums.js";
|
||||
import { ACTOR_TYPES } from "../constants.js";
|
||||
import { TextRollAlchimie } from "./textroll/text-roll-alchimie.js";
|
||||
import { TextRollCaracCompetence } from "./textroll/text-roll-carac-competence.js";
|
||||
import { TextRollFormula } from "./textroll/text-roll-formula.js";
|
||||
import { TextRollManager } from "./textroll/text-roll-formatter.js";
|
||||
|
||||
const TEXT_ROLL_MANAGERS = [
|
||||
new TextRollAlchimie(),
|
||||
new TextRollCaracCompetence(),
|
||||
new TextRollFormula()]
|
||||
|
||||
export class RdDTextEditor {
|
||||
static registerChatCallbacks(html) {
|
||||
html.on("click", '.roll-text', async event => await RdDTextEditor.rollText(event))
|
||||
}
|
||||
|
||||
static async enrichHTML(text, object, options = {showlink:true}) {
|
||||
const context = {
|
||||
text,
|
||||
object,
|
||||
options,
|
||||
competences: await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage),
|
||||
}
|
||||
|
||||
for (let manager of TEXT_ROLL_MANAGERS) {
|
||||
context.code = manager.code
|
||||
context.template = manager.template
|
||||
context.text = await manager.onReplaceRoll(context);
|
||||
}
|
||||
|
||||
return await TextEditor.enrichHTML(context.text, {
|
||||
relativeTo: object,
|
||||
secrets: object?.isOwner,
|
||||
async: true
|
||||
})
|
||||
}
|
||||
|
||||
static async _applyReplaceAll(manager, context) {
|
||||
context.code = manager.code
|
||||
context.template = manager.template
|
||||
context.text = await manager.onReplaceRoll(context);
|
||||
return context.text
|
||||
}
|
||||
|
||||
static getEventElement(event) {
|
||||
return $(event.currentTarget)?.parents(".roll-text-link");
|
||||
}
|
||||
|
||||
static async rollText(event, actor) {
|
||||
const code = TextRollManager.getNode(event)?.data('code')
|
||||
const manager = TEXT_ROLL_MANAGERS.find(it => it.code == code)
|
||||
if (manager) {
|
||||
await manager.onRollText(event, actor)
|
||||
}
|
||||
}
|
||||
|
||||
static async chatRollText(event) {
|
||||
const node = TextRollManager.getNode(event);
|
||||
if (node) {
|
||||
const code = node.data('code')
|
||||
const param = node.data('json')
|
||||
const manager = TEXT_ROLL_MANAGERS.find(it => it.code == code)
|
||||
|
||||
const text = await TextRollManager.createRollText(
|
||||
{
|
||||
code,
|
||||
template: manager.template,
|
||||
options: { showLink: false }
|
||||
},
|
||||
param)
|
||||
ChatMessage.create({
|
||||
content: text
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
79
module/apps/textroll/text-roll-alchimie.js
Normal file
@ -0,0 +1,79 @@
|
||||
import "../xregexp-all.js";
|
||||
import { ACTOR_TYPES, ITEM_TYPES } from "../../constants.js";
|
||||
import { RdDCarac } from "../../rdd-carac.js";
|
||||
import { RdDUtility } from "../../rdd-utility.js";
|
||||
import { RdDAlchimie } from "../../rdd-alchimie.js";
|
||||
import { TextRollManager } from "./text-roll-formatter.js";
|
||||
|
||||
const REGEX_ALCHIMIE_TERMES = "(?<termes>(\\w|-)+)"
|
||||
const REGEX_ALCHIMIE_MANIP = "(?<manip>(couleur|consistance))"
|
||||
const XREGEXP_ROLL_ALCHIMIE = XRegExp("@roll\\[" + REGEX_ALCHIMIE_MANIP + "\\s+" + REGEX_ALCHIMIE_TERMES + "\\]", 'giu')
|
||||
const XREGEXP_ROLL_ALCHIMIE_MANIP = XRegExp("@" + REGEX_ALCHIMIE_MANIP + "\\{" + REGEX_ALCHIMIE_TERMES + "\\}", 'giu')
|
||||
|
||||
/**
|
||||
* classe pour gérer les jets d'alchimie
|
||||
*/
|
||||
export class TextRollAlchimie {
|
||||
get code() { return 'alchimie' }
|
||||
get template() { return `systems/foundryvtt-reve-de-dragon/templates/apps/textroll/link-text-roll-alchimie.hbs` }
|
||||
|
||||
async onReplaceRoll(context) {
|
||||
const handler = new AlchimieTextBuilder(context)
|
||||
return await handler.replaceAll()
|
||||
}
|
||||
|
||||
async onRollText(event, actor) {
|
||||
actor = this.getSelectedActor(actor)
|
||||
if (actor) {
|
||||
const node = TextRollManager.getNode(event)
|
||||
const recetteId = node.data('recetteid')
|
||||
const manip = node.data('manip')
|
||||
const termes = node.data('termes')
|
||||
if (recetteId) {
|
||||
await actor.effectuerTacheAlchimie(recetteId, manip, termes)
|
||||
}
|
||||
else {
|
||||
const carac = RdDCarac.caracDetails(RdDAlchimie.getCaracTache(manip))
|
||||
const diff = RdDAlchimie.getDifficulte(termes)
|
||||
await actor.rollCaracCompetence(carac.code, 'Alchimie', diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getSelectedActor(actor) {
|
||||
actor = actor ?? RdDUtility.getSelectedActor()
|
||||
if (actor && actor.type == ACTOR_TYPES.personnage) {
|
||||
return actor
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
class AlchimieTextBuilder {
|
||||
constructor(context) {
|
||||
this.context = context
|
||||
}
|
||||
|
||||
async replaceAll() {
|
||||
await XRegExp.forEach(this.context.text, XREGEXP_ROLL_ALCHIMIE, async (rollMatch, i) => await this.replaceMatch(rollMatch, i))
|
||||
await XRegExp.forEach(this.context.text, XREGEXP_ROLL_ALCHIMIE_MANIP, async (rollMatch, i) => await this.replaceMatch(rollMatch, i))
|
||||
return this.context.text
|
||||
}
|
||||
|
||||
async replaceMatch(rollMatch, i) {
|
||||
if (rollMatch.termes && rollMatch.manip) {
|
||||
const manip = rollMatch.manip
|
||||
const termes = rollMatch.termes
|
||||
const carac = RdDCarac.caracDetails(RdDAlchimie.getCaracTache(manip))
|
||||
const diff = RdDAlchimie.getDifficulte(termes)
|
||||
const recette = (this.context.object instanceof Item && this.context.object.type == ITEM_TYPES.recettealchimique) ? this.context.object : undefined
|
||||
const replacement = await TextRollManager.createRollText(this.context,
|
||||
{
|
||||
code: this.context.code,
|
||||
manip, termes, carac, diff, recetteid: recette?.id,
|
||||
})
|
||||
this.context.text = this.context.text.replace(rollMatch[0], replacement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
98
module/apps/textroll/text-roll-carac-competence.js
Normal file
@ -0,0 +1,98 @@
|
||||
import "../xregexp-all.js";
|
||||
import { RdDCarac } from "../../rdd-carac.js";
|
||||
import { RdDItemCompetence } from "../../item-competence.js";
|
||||
import { RdDUtility } from "../../rdd-utility.js";
|
||||
import { TextRollManager } from "./text-roll-formatter.js";
|
||||
|
||||
const REGECP_CARAC = "(?<carac>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+)"
|
||||
const REGEXP_COMP = "(\\/(?<competence>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+))?"
|
||||
const REGEXP_DIFF = "(/(?<diff>[\\+\\-]?\\d+(d\\d+)?))?"
|
||||
const REGEXP_ROLL_CARAC_COMP = REGECP_CARAC + REGEXP_COMP + REGEXP_DIFF
|
||||
const XREGEXP_ROLL_CARAC_COMP = XRegExp("@roll\\[" + REGEXP_ROLL_CARAC_COMP + "\\]", 'giu')
|
||||
|
||||
/**
|
||||
* classe pour gérer les jets de caractéristique/compétence depuis
|
||||
* les journaux/descriptions
|
||||
*/
|
||||
export class TextRollCaracCompetence {
|
||||
get code() { return 'carac' }
|
||||
get template() { return `systems/foundryvtt-reve-de-dragon/templates/apps/textroll/link-text-roll-carac-competence.hbs` }
|
||||
|
||||
async onReplaceRoll(context) {
|
||||
const handler = new CaracCompetenceTextBuilder(context)
|
||||
return await handler.replaceAll()
|
||||
}
|
||||
|
||||
async onRollText(event, actor) {
|
||||
const node = TextRollManager.getNode(event)
|
||||
const caracCode = node.data('carac-code')
|
||||
if (caracCode) {
|
||||
const competence = node.data('competence')
|
||||
const diff = await this.calculDiff(node)
|
||||
const actors = this.getSelectedActors(actor)
|
||||
actors.forEach(async it => await this.doRoll(it, caracCode, competence, diff))
|
||||
}
|
||||
}
|
||||
|
||||
async calculDiff(node) {
|
||||
const diff = node.data('diff') ?? 0
|
||||
if (!Number.isInteger(diff)) {
|
||||
const roll = new Roll(diff)
|
||||
await roll.evaluate()
|
||||
await roll.toMessage({ flavor: `La difficulté de ${diff} a donné ${roll.total}` })
|
||||
return roll.total
|
||||
}
|
||||
return diff
|
||||
}
|
||||
|
||||
async doRoll(actor, caracCode, competence, diff) {
|
||||
caracCode = actor.mapCarac(caracCode)
|
||||
if (caracCode) {
|
||||
if (competence) {
|
||||
await actor.rollCaracCompetence(caracCode, competence, diff)
|
||||
}
|
||||
else {
|
||||
await actor.rollCarac(caracCode, { diff })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getSelectedActors(actor) {
|
||||
const selected = canvas.tokens.controlled.map(it => it.actor).filter(it => it)
|
||||
if (selected.length > 0) {
|
||||
return selected
|
||||
}
|
||||
actor = actor ?? RdDUtility.getSelectedActor()
|
||||
if (actor) {
|
||||
return [actor]
|
||||
}
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
class CaracCompetenceTextBuilder {
|
||||
constructor(context) {
|
||||
this.context = context
|
||||
}
|
||||
|
||||
async replaceAll() {
|
||||
await XRegExp.forEach(this.context.text, XREGEXP_ROLL_CARAC_COMP, async (rollMatch, i) => await this.replaceMatch(rollMatch, i))
|
||||
return this.context.text
|
||||
}
|
||||
|
||||
async replaceMatch(rollMatch, i) {
|
||||
const carac = RdDCarac.caracDetails(rollMatch.carac)
|
||||
if (carac) {
|
||||
const competence = rollMatch.competence ? RdDItemCompetence.findCompetence(this.context.competences, rollMatch.competence) : undefined
|
||||
const replacement = await TextRollManager.createRollText(this.context,
|
||||
{
|
||||
code: this.context.code,
|
||||
carac: carac,
|
||||
competence: competence?.name,
|
||||
diff: rollMatch.diff,
|
||||
})
|
||||
this.context.text = this.context.text.replace(rollMatch[0], replacement)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
13
module/apps/textroll/text-roll-formatter.js
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
export class TextRollManager {
|
||||
|
||||
static async createRollText(context, param) {
|
||||
return await renderTemplate(context.template, {
|
||||
param, options: context.options
|
||||
})
|
||||
}
|
||||
|
||||
static getNode(event) {
|
||||
return $(event.currentTarget)?.parents(".roll-text-link");
|
||||
}
|
||||
}
|
51
module/apps/textroll/text-roll-formula.js
Normal file
@ -0,0 +1,51 @@
|
||||
import "../xregexp-all.js";
|
||||
import { TextRollManager } from "./text-roll-formatter.js";
|
||||
|
||||
const REGEXP_ROLL_FORMULA = "(?<formula>[^\\[\\]]+)"
|
||||
const XREGEXP_ROLL_FORMULA = XRegExp("@roll\\[" + REGEXP_ROLL_FORMULA + "\\]", 'giu')
|
||||
|
||||
/**
|
||||
* classe pour gérer les jets de dés (formules Foundry)
|
||||
*/
|
||||
export class TextRollFormula {
|
||||
get code() { return 'formula' }
|
||||
get template() { return `systems/foundryvtt-reve-de-dragon/templates/apps/textroll/link-text-roll-formula.hbs` }
|
||||
|
||||
async onReplaceRoll(context) {
|
||||
const handler = new FormulaTextBuilder(context)
|
||||
return await handler.replaceAll()
|
||||
}
|
||||
|
||||
async onRollText(event, actor) {
|
||||
const node = TextRollManager.getNode(event)
|
||||
const rollFormula = node.data('formula')
|
||||
if (rollFormula) {
|
||||
const roll = new Roll(rollFormula)
|
||||
await roll.evaluate()
|
||||
await roll.toMessage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FormulaTextBuilder {
|
||||
constructor(context) {
|
||||
this.context = context
|
||||
}
|
||||
|
||||
async replaceAll() {
|
||||
await XRegExp.forEach(this.context.text, XREGEXP_ROLL_FORMULA,
|
||||
async (rollMatch, i) => await this.replaceMatch(rollMatch, i))
|
||||
return this.context.text
|
||||
}
|
||||
|
||||
async replaceMatch(rollMatch, i) {
|
||||
if (rollMatch.formula) {
|
||||
const replacement = await TextRollManager.createRollText(this.context,
|
||||
{
|
||||
code: this.context.code,
|
||||
formula: rollMatch.formula,
|
||||
})
|
||||
this.context.text = this.context.text.replace(rollMatch[0], replacement)
|
||||
}
|
||||
}
|
||||
}
|
8225
module/apps/xregexp-all.js
Normal file
@ -1,5 +1,7 @@
|
||||
import { Misc } from "./misc.js";
|
||||
import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
|
||||
import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
|
||||
|
||||
|
||||
/**
|
||||
@ -7,15 +9,20 @@ import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
|
||||
*/
|
||||
export class ChatUtility {
|
||||
|
||||
static async init() {
|
||||
Hooks.on("renderChatMessage", async (app, html, msg) => await ChatUtility.onRenderChatMessage(app, html, msg))
|
||||
Hooks.on("createChatMessage", async (chatMessage, options, id) => await ChatUtility.onCreateChatMessage(chatMessage, options, id))
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static onSocketMessage(sockmsg) {
|
||||
switch (sockmsg.msg) {
|
||||
case "msg_delete_chat_message": return ChatUtility.onRemoveMessages(sockmsg.data);
|
||||
case "msg_user_ui_notifications": return ChatUtility.onNotifyUser(sockmsg.data);
|
||||
case "msg_gm_chat_message": return ChatUtility.handleGMChatMessage(sockmsg.data)
|
||||
case "msg_delete_chat_message": return ChatUtility.onRemoveMessages(sockmsg.data)
|
||||
case "msg_user_ui_notifications": return ChatUtility.onNotifyUser(sockmsg.data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static notifyUser(userId, level = 'info', message) {
|
||||
const socketData = {
|
||||
@ -43,7 +50,7 @@ export class ChatUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static onRemoveMessages(socketData) {
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
if (Misc.isFirstConnectedGM()) {
|
||||
if (socketData.part) {
|
||||
const toDelete = game.messages.filter(it => it.content.includes(socketData.part));
|
||||
toDelete.forEach(it => it.delete());
|
||||
@ -57,7 +64,7 @@ export class ChatUtility {
|
||||
/* -------------------------------------------- */
|
||||
|
||||
static removeMessages(socketData) {
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
if (Misc.isFirstConnectedGM()) {
|
||||
ChatUtility.onRemoveMessages(socketData);
|
||||
}
|
||||
else {
|
||||
@ -71,94 +78,107 @@ export class ChatUtility {
|
||||
}
|
||||
|
||||
static removeChatMessageId(messageId) {
|
||||
if (messageId){
|
||||
if (messageId) {
|
||||
ChatUtility.removeMessages({ messageId: messageId });
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async createChatWithRollMode(name, chatOptions) {
|
||||
return await ChatUtility.createChatMessage(name, game.settings.get("core", "rollMode"), chatOptions);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async createChatMessage(name, rollMode, chatOptions) {
|
||||
switch (rollMode) {
|
||||
static async createChatWithRollMode(messageData, actor = undefined) {
|
||||
switch (game.settings.get("core", "rollMode")) {
|
||||
case "blindroll": // GM only
|
||||
if (!game.user.isGM) {
|
||||
ChatUtility.blindMessageToGM(chatOptions);
|
||||
|
||||
chatOptions.whisper = [game.user.id];
|
||||
chatOptions.content = "Message envoyé en aveugle au Gardien";
|
||||
ChatUtility.blindMessageToGM(messageData)
|
||||
messageData.whisper = [game.user];
|
||||
messageData.content = "Message envoyé en aveugle au Gardien"
|
||||
}
|
||||
else {
|
||||
chatOptions.whisper = ChatUtility.getUsers(user => user.isGM);
|
||||
messageData.whisper = ChatUtility.getGMs()
|
||||
}
|
||||
break;
|
||||
default:
|
||||
chatOptions.whisper = ChatUtility.getWhisperRecipients(rollMode, name);
|
||||
break;
|
||||
break
|
||||
case "gmroll":
|
||||
messageData.whisper = ChatUtility.getOwners(actor)
|
||||
break
|
||||
case "selfroll":
|
||||
messageData.whisper = [game.user]
|
||||
break
|
||||
}
|
||||
chatOptions.alias = chatOptions.alias || name;
|
||||
return await ChatMessage.create(chatOptions);
|
||||
messageData.alias = messageData.alias ?? actor?.name ?? game.user.name
|
||||
return await ChatMessage.create(messageData)
|
||||
}
|
||||
|
||||
static getOwners(document) {
|
||||
return game.users.filter(it => document.getUserLevel(it) == CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)
|
||||
}
|
||||
|
||||
static getUserAndGMs() {
|
||||
return [game.user, ...ChatUtility.getGMs()]
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static prepareChatMessage(rollMode, name) {
|
||||
return {
|
||||
user: game.user.id,
|
||||
whisper: ChatUtility.getWhisperRecipients(rollMode, name)
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getWhisperRecipients(rollMode, name) {
|
||||
switch (rollMode) {
|
||||
case "blindroll": return ChatUtility.getUsers(user => user.isGM);
|
||||
case "gmroll": return ChatUtility.getWhisperRecipientsAndGMs(name);
|
||||
case "selfroll": return [game.user.id];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getWhisperRecipientsAndGMs(name) {
|
||||
let recep1 = ChatMessage.getWhisperRecipients(name) || [];
|
||||
return recep1.concat(ChatMessage.getWhisperRecipients('GM'));
|
||||
static getMultipleActorsOwners(...actors) {
|
||||
return Misc.concat(actors.map(it => it == undefined ? [] : ChatUtility.getOwners(it)))
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getUsers(filter) {
|
||||
return game.users.filter(filter).map(user => user.id);
|
||||
return game.users.filter(filter)
|
||||
}
|
||||
|
||||
static getGMs() {
|
||||
return game.users.filter(user => user.isGM)
|
||||
}
|
||||
|
||||
static applyRollMode(chatMessageData = {}, rollMode = game.settings.get("core", "rollMode")) {
|
||||
switch (rollMode) {
|
||||
case "blindroll":
|
||||
chatMessageData.blind = true
|
||||
chatMessageData.whisper = ChatUtility.getGMs()
|
||||
break
|
||||
case "gmroll":
|
||||
chatMessageData.whisper = ChatUtility.getGMs()
|
||||
chatMessageData.blind = false
|
||||
break
|
||||
case "roll":
|
||||
chatMessageData.whisper = ChatUtility.getUsers(user => user.active)
|
||||
chatMessageData.blind = false
|
||||
break
|
||||
case "selfroll":
|
||||
chatMessageData.whisper = [game.user]
|
||||
chatMessageData.blind = false
|
||||
break
|
||||
}
|
||||
return chatMessageData
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static blindMessageToGM(chatOptions) {
|
||||
let chatGM = duplicate(chatOptions);
|
||||
chatGM.whisper = ChatUtility.getUsers(user => user.isGM);
|
||||
chatGM.content = "Message aveugle de " + game.user.name + "<br>" + chatOptions.content;
|
||||
console.log("blindMessageToGM", chatGM);
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_gm_chat_message", data: chatGM });
|
||||
const chatGM = foundry.utils.duplicate(chatOptions)
|
||||
chatGM.content = "Message aveugle de " + game.user.name + "<br>" + chatOptions.content
|
||||
console.log("blindMessageToGM", chatGM)
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_gm_chat_message", data: chatGM })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static handleGMChatMessage(socketData) {
|
||||
console.log("blindMessageToGM", socketData);
|
||||
if (game.user.isGM) { // message privé pour GM only
|
||||
socketData.user = game.user.id;
|
||||
ChatMessage.create(socketData);
|
||||
if (Misc.isFirstConnectedGM()) {
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
whisper: ChatUtility.getGMs(),
|
||||
content: socketData.content
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
static async setMessageData(chatMessage, key, flag) {
|
||||
if (flag) {
|
||||
await chatMessage.setFlag(SYSTEM_RDD, key, JSON.stringify(flag));
|
||||
if (flag && chatMessage.isAuthor) {
|
||||
await chatMessage.setFlag(SYSTEM_RDD, key, flag)
|
||||
}
|
||||
}
|
||||
|
||||
static getMessageData(chatMessage, key) {
|
||||
const json = chatMessage.getFlag(SYSTEM_RDD, key);
|
||||
return json ? JSON.parse(json) : undefined;
|
||||
return chatMessage.getFlag(SYSTEM_RDD, key);
|
||||
}
|
||||
|
||||
static getChatMessage(event) {
|
||||
@ -166,4 +186,20 @@ export class ChatUtility {
|
||||
return game.messages.get(chatMessageId);
|
||||
}
|
||||
|
||||
static async onRenderChatMessage(chatMessage, html, data) {
|
||||
const rddTimestamp = chatMessage.getFlag(SYSTEM_RDD, 'rdd-timestamp')
|
||||
if (rddTimestamp) {
|
||||
const timestamp = new RdDTimestamp(rddTimestamp);
|
||||
const timestampData = timestamp.toCalendrier();
|
||||
const dateHeure = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/common/date-heure.hbs', timestampData);
|
||||
html.find('header.message-header .message-sender').after(dateHeure)
|
||||
}
|
||||
}
|
||||
|
||||
static async onCreateChatMessage(chatMessage, options, id) {
|
||||
if (chatMessage.isAuthor) {
|
||||
await chatMessage.setFlag(SYSTEM_RDD, 'rdd-timestamp', game.system.rdd.calendrier.getTimestamp());
|
||||
await chatMessage.update({ content: await RdDTextEditor.enrichHTML(chatMessage.content, undefined, {showLink:false}) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
168
module/coeur/rdd-coeur.js
Normal file
@ -0,0 +1,168 @@
|
||||
import { RdDBaseActor } from "../actor/base-actor.js";
|
||||
import { ChatUtility } from "../chat-utility.js";
|
||||
|
||||
const INFO_COEUR = 'info-coeur';
|
||||
|
||||
export class RdDCoeur {
|
||||
static registerChatCallbacks(html) {
|
||||
html.on("click", 'a.accepter-tendre-moment', event => {
|
||||
RdDCoeur.accepterTendreMoment(RdDCoeur.extractInfoCoeur(event))
|
||||
})
|
||||
html.on("click", 'a.refuser-tendre-moment', event => {
|
||||
RdDCoeur.refuserTendreMoment(RdDCoeur.extractInfoCoeur(event))
|
||||
})
|
||||
html.on("click", 'a.perdre-point-coeur-douceur', event => {
|
||||
RdDCoeur.perdreEnDouceur(
|
||||
RdDCoeur.extractInfoCoeur(event),
|
||||
event.currentTarget.attributes['data-actor-id'].value)
|
||||
})
|
||||
}
|
||||
|
||||
static addTagsInfoCoeur(infoCoeur, chatMessage = undefined) {
|
||||
if (chatMessage) {
|
||||
infoCoeur.chatMessageId = chatMessage.id
|
||||
}
|
||||
else {
|
||||
chatMessage = game.messages.get(infoCoeur.chatMessageId)
|
||||
}
|
||||
ChatUtility.setMessageData(chatMessage, INFO_COEUR, infoCoeur);
|
||||
}
|
||||
|
||||
static extractInfoCoeur(event) {
|
||||
const chatMesage = ChatUtility.getChatMessage(event);
|
||||
return ChatUtility.getMessageData(chatMesage, INFO_COEUR)
|
||||
}
|
||||
|
||||
static getInfoCoeur(sourceActorId, targetActorId) {
|
||||
const sourceActor = game.actors.get(sourceActorId)
|
||||
const targetActor = game.actors.get(targetActorId)
|
||||
if (sourceActor && targetActor) {
|
||||
return {
|
||||
source: {
|
||||
actor: RdDBaseActor.extractActorMin(sourceActor),
|
||||
coeur: sourceActor.getPointsCoeur(targetActorId),
|
||||
},
|
||||
target: {
|
||||
actor: RdDBaseActor.extractActorMin(targetActor),
|
||||
coeur: targetActor.getPointsCoeur(sourceActorId),
|
||||
}
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
static async toggleSubActeurCoeur(actorId, subActorId, toggleCoeur) {
|
||||
const actor = game.actors.get(actorId)
|
||||
const amoureux = actor.getSuivant(subActorId)
|
||||
if (toggleCoeur <= amoureux.coeur) {
|
||||
if (toggleCoeur > amoureux.prochainCoeur) {
|
||||
toggleCoeur = amoureux.coeur
|
||||
}
|
||||
else {
|
||||
toggleCoeur = amoureux.coeur - 1
|
||||
}
|
||||
}
|
||||
else if (toggleCoeur <= amoureux.prochainCoeur) {
|
||||
toggleCoeur = Math.max(amoureux.coeur, toggleCoeur - 1)
|
||||
}
|
||||
actor.setPointsCoeur(subActorId, Math.max(0, Math.min(toggleCoeur, 4)))
|
||||
}
|
||||
|
||||
static async applyCoeurChateauDormant(actor, message) {
|
||||
const newSuivants = foundry.utils.duplicate(actor.system.subacteurs.suivants)
|
||||
let count = 0
|
||||
newSuivants.forEach(async link => {
|
||||
const suivant = game.actors.get(link.id)
|
||||
const prochainCoeur = link.prochainCoeur ?? 0;
|
||||
const coeurCourant = link.coeur ?? 0;
|
||||
const diff = prochainCoeur - coeurCourant
|
||||
if (diff < 0) {
|
||||
await actor.moralIncDec(-4);
|
||||
link.coeur = Math.max(0, coeurCourant - 1)
|
||||
link.prochainCoeur = link.coeur
|
||||
message.content += `<br>Votre cœur brisé pour ${suivant.name} vous fait perdre 4 points de moral, il vous reste ${link.coeur} points de Cœur.`
|
||||
count++
|
||||
}
|
||||
else if (diff > 0) {
|
||||
link.coeur = Math.min(prochainCoeur, 4)
|
||||
message.content += `<br>Votre cœur bat fort, vous avez maintenant ${link.coeur} points de Cœur pour ${suivant.name}.`
|
||||
link.prochainCoeur = link.coeur
|
||||
count++
|
||||
}
|
||||
}
|
||||
)
|
||||
if (count > 0) {
|
||||
await actor.update({ 'system.subacteurs.suivants': newSuivants });
|
||||
}
|
||||
}
|
||||
|
||||
static async startSubActeurTendreMoment(actorId, subActeurId) {
|
||||
const infoCoeur = RdDCoeur.getInfoCoeur(actorId, subActeurId)
|
||||
if (infoCoeur.target?.actor?.id) {
|
||||
// TODO: passer par une fenêtre pour saisir sa proposition (lieu, heure, ...)
|
||||
const chatMessage = await ChatMessage.create({
|
||||
whisper: ChatUtility.getOwners(infoCoeur.target.actor),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-proposer-tendre-moment.hbs`, infoCoeur)
|
||||
})
|
||||
RdDCoeur.addTagsInfoCoeur(infoCoeur, chatMessage)
|
||||
}
|
||||
}
|
||||
|
||||
static async accepterTendreMoment(infoCoeur) {
|
||||
const target = game.actors.get(infoCoeur.target.actor.id)
|
||||
if (!target.isOwner) {
|
||||
ui.notifications.warn(`vous ne pouvez pas accepter pour ${infoCoeur.target.actor.name}`)
|
||||
return
|
||||
}
|
||||
ChatUtility.removeChatMessageId(infoCoeur.chatMessageId)
|
||||
|
||||
infoCoeur.target.jetTendre = (await (new Roll('1d6').evaluate())).total
|
||||
infoCoeur.source.jetTendre = (await (new Roll('1d6').evaluate())).total
|
||||
const diff = Math.abs(infoCoeur.source.jetTendre - infoCoeur.target.jetTendre)
|
||||
for (let amoureux of [infoCoeur.source, infoCoeur.target]) {
|
||||
const actorAmoureux = game.actors.get(amoureux.actor.id);
|
||||
amoureux.situation = diff <= amoureux.coeur ? 'heureux' : 'neutre'
|
||||
amoureux.gainMoral = await actorAmoureux.jetDeMoral(amoureux.situation)
|
||||
}
|
||||
const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-accepter-tendre-moment.hbs`, infoCoeur)
|
||||
const chatMessage = await ChatMessage.create({
|
||||
whisper: ChatUtility.getMultipleActorsOwners(infoCoeur.source?.actor, infoCoeur.target?.actor),
|
||||
content: chatHtml
|
||||
})
|
||||
RdDCoeur.addTagsInfoCoeur(infoCoeur, chatMessage)
|
||||
}
|
||||
|
||||
static async refuserTendreMoment(infoCoeur) {
|
||||
const target = game.actors.get(infoCoeur.target.actor.id)
|
||||
if (!target.isOwner) {
|
||||
ui.notifications.warn(`vous ne pouvez pas refuser pour ${infoCoeur.target.actor.name}`)
|
||||
return
|
||||
}
|
||||
ChatUtility.removeChatMessageId(infoCoeur.chatMessageId)
|
||||
const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-refuser-tendre-moment.hbs`, infoCoeur)
|
||||
await ChatMessage.create({
|
||||
whisper: ChatUtility.getMultipleActorsOwners(infoCoeur.source?.actor, infoCoeur.target?.actor),
|
||||
content: chatHtml
|
||||
});
|
||||
}
|
||||
|
||||
static async perdreEnDouceur(infoCoeur, actorId) {
|
||||
const [amoureux, partenaire] = (infoCoeur.source.actor.id == actorId
|
||||
? [infoCoeur.source, infoCoeur.target]
|
||||
: (infoCoeur.target.actor.id == actorId
|
||||
? [infoCoeur.target, infoCoeur.source]
|
||||
: [undefined, undefined]))
|
||||
|
||||
if (amoureux.perteCoeur) {
|
||||
ui.notifications.warn(`Le point de cœur a déjà été perdu`)
|
||||
}
|
||||
else if (amoureux.coeur > 0) {
|
||||
const actor = game.actors.get(actorId)
|
||||
if (actor.isOwner) {
|
||||
await actor.setPointsCoeur(partenaire?.actor.id, amoureux.coeur - 1, { immediat: true })
|
||||
amoureux.perteCoeur = true
|
||||
RdDCoeur.addTagsInfoCoeur(infoCoeur)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,108 @@
|
||||
export const SYSTEM_RDD = 'foundryvtt-reve-de-dragon';
|
||||
export const SYSTEM_SOCKET_ID = 'system.foundryvtt-reve-de-dragon';
|
||||
export const LOG_HEAD = 'RdD | ';
|
||||
export const SYSTEM_RDD = 'foundryvtt-reve-de-dragon'
|
||||
export const SYSTEM_SOCKET_ID = 'system.foundryvtt-reve-de-dragon'
|
||||
export const LOG_HEAD = 'RdD | '
|
||||
|
||||
export const HIDE_DICE = 'hide';
|
||||
export const SHOW_DICE = 'show';
|
||||
export const HIDE_DICE = 'hide'
|
||||
export const SHOW_DICE = 'show'
|
||||
|
||||
export const ENTITE_INCARNE = 'incarne';
|
||||
export const ENTITE_NONINCARNE = 'nonincarne';
|
||||
export const ENTITE_BLURETTE = 'blurette';
|
||||
export const ENTITE_INCARNE = 'incarne'
|
||||
export const ENTITE_NONINCARNE = 'nonincarne'
|
||||
export const ENTITE_BLURETTE = 'blurette'
|
||||
|
||||
export const RDD_CONFIG = {
|
||||
niveauEthylisme : [
|
||||
{value: "1", label: "Aucun"},
|
||||
{value: "0", label: "Eméché (0)"},
|
||||
{value: "-1", label: "Gris (-1)"},
|
||||
{value: "-2", label: "Pinté (-2)"},
|
||||
{value: "-3", label: "Pas Frais (-3)"},
|
||||
{value: "-4", label: "Ivre (-4)"},
|
||||
{value: "-5", label: "Bu (-5)"},
|
||||
{value: "-6", label: "Complètement fait (-6)"},
|
||||
{value: "-7", label: "Ivre mort (-7)"}
|
||||
],
|
||||
categorieEntite: {
|
||||
"cauchemar": "Cauchemar",
|
||||
"reve": "Rêve"
|
||||
},
|
||||
typeEntite: {
|
||||
"incarne": "Incarnée",
|
||||
"nonincarne": "Non Incarnée",
|
||||
"blurette": "Blurette"
|
||||
},
|
||||
heuresRdD : [
|
||||
{value : "vaisseau", label: "Vaisseau", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd01.webp"},
|
||||
{value : "sirene", label: "Sirène", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd02.webp"},
|
||||
{value : "faucon", label: "Faucon", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd03.webp"},
|
||||
{value : "couronne", label: "Couronne", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd04.webp"},
|
||||
{value : "dragon", label: "Dragon", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd05.webp"},
|
||||
{value : "epees", label: "Epées", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd06.webp"},
|
||||
{value : "lyre", label: "Lyre", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd07.webp"},
|
||||
{value : "serpent", label: "Serpent", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd08.webp"},
|
||||
{value : "poissonacrobate", label: "Poisson Acrobate", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd09.webp"},
|
||||
{value : "araignee", label: "Araignée", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd10.webp"},
|
||||
{value : "roseau", label: "Roseau", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd11.webp"},
|
||||
{value : "chateaudormant", label: "Chateau Dormant", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd12.webp"}
|
||||
],
|
||||
raretes: [
|
||||
{value: "Commune", label: "Commune"},
|
||||
{value: "Frequente", label: "Fréquente"},
|
||||
{value: "Rare", label: "Rare"},
|
||||
{value: "Rarissime", label: "Rarissime"}
|
||||
]
|
||||
}
|
||||
|
||||
export const ACTOR_TYPES = {
|
||||
personnage: 'personnage',
|
||||
creature: 'creature',
|
||||
entite: 'entite',
|
||||
commerce: 'commerce',
|
||||
vehicule: 'vehicule'
|
||||
}
|
||||
|
||||
export const ITEM_TYPES = {
|
||||
competence: 'competence',
|
||||
competencecreature: 'competencecreature',
|
||||
empoignade: 'empoignade',
|
||||
possession: 'possession',
|
||||
blessure: 'blessure',
|
||||
maladie: 'maladie',
|
||||
poison: 'poison',
|
||||
arme: 'arme',
|
||||
armure: 'armure',
|
||||
conteneur: 'conteneur',
|
||||
objet: 'objet',
|
||||
monnaie: 'monnaie',
|
||||
gemme: 'gemme',
|
||||
munition: 'munition',
|
||||
nourritureboisson: 'nourritureboisson',
|
||||
herbe: 'herbe',
|
||||
plante: 'plante',
|
||||
ingredient: 'ingredient',
|
||||
faune: 'faune',
|
||||
livre: 'livre',
|
||||
potion: 'potion',
|
||||
service: 'service',
|
||||
musique: 'musique',
|
||||
danse: 'danse',
|
||||
chant: 'chant',
|
||||
jeu: 'jeu',
|
||||
race: 'race',
|
||||
recettecuisine: 'recettecuisine',
|
||||
oeuvre: 'oeuvre',
|
||||
recettealchimique: 'recettealchimique',
|
||||
tache: 'tache',
|
||||
sort: 'sort',
|
||||
sortreserve: 'sortreserve',
|
||||
rencontre: 'rencontre',
|
||||
queue: 'queue',
|
||||
ombre: 'ombre',
|
||||
souffle: 'souffle',
|
||||
tete: 'tete',
|
||||
casetmr: 'casetmr',
|
||||
meditation: 'meditation',
|
||||
signedraconique: 'signedraconique',
|
||||
tarot: 'tarot',
|
||||
nombreastral: 'nombreastral',
|
||||
extraitpoetique: 'extraitpoetique',
|
||||
}
|
||||
|
84
module/dialog-choix-xp-carac.js
Normal file
@ -0,0 +1,84 @@
|
||||
|
||||
export class DialogChoixXpCarac extends Dialog {
|
||||
|
||||
static async choix(actor, xpData, caracs) {
|
||||
caracs = caracs.map(it => foundry.utils.mergeObject({ ajout: 0 }, it))
|
||||
xpData = foundry.utils.mergeObject({ reste: xpData.xpCarac }, xpData)
|
||||
const dialogData = {
|
||||
title: `Choisissez la répartition d'expérience`,
|
||||
content: await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-choix-xp-carac.hbs", {
|
||||
actor,
|
||||
caracDerivee: actor.findCaracByName(xpData.caracName),
|
||||
xpData,
|
||||
caracs
|
||||
}),
|
||||
}
|
||||
|
||||
const dialogOptions = {
|
||||
classes: ["rdd-dialog-select"],
|
||||
width: 400,
|
||||
height: 'fit-content',
|
||||
'z-index': 99999
|
||||
}
|
||||
new DialogChoixXpCarac(dialogData, dialogOptions, actor, xpData, caracs).render(true)
|
||||
}
|
||||
|
||||
constructor(dialogData, dialogOptions, actor, xpData, caracs) {
|
||||
dialogData = foundry.utils.mergeObject(dialogData, {
|
||||
default: 'appliquer',
|
||||
buttons: {
|
||||
'appliquer': { icon:'<i class="fa-solid fa-check"></i>', label: "Ajouter la répartition", callback: it => this.appliquerSelection() }
|
||||
}
|
||||
})
|
||||
super(dialogData, dialogOptions)
|
||||
this.actor = actor
|
||||
this.xpData = xpData
|
||||
this.caracs = caracs
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
//TODO
|
||||
super.activateListeners(html)
|
||||
this.html = html
|
||||
this.html.find("li.xpCarac-option .xpCarac-moins").click(event =>
|
||||
this.ajouterXp(event, -1)
|
||||
)
|
||||
this.html.find("li.xpCarac-option .xpCarac-plus").click(event =>
|
||||
this.ajouterXp(event, 1)
|
||||
)
|
||||
}
|
||||
|
||||
async ajouterXp(event, delta) {
|
||||
const liCarac = this.html.find(event.currentTarget)?.parents("li.xpCarac-option")
|
||||
const label = liCarac?.data("carac-label")
|
||||
const carac = this.caracs.find(c => c.label == label)
|
||||
if (carac.ajout + delta < 0) {
|
||||
ui.notifications.warn(`Impossible de diminuer les points à répartir en ${carac.label} en dessous de 0`)
|
||||
return
|
||||
}
|
||||
if (this.xpData.reste - delta < 0) {
|
||||
ui.notifications.warn(`Il ne reste plus de points à répartir en ${carac.label}`)
|
||||
return
|
||||
}
|
||||
carac.ajout += delta
|
||||
this.xpData.reste -= delta
|
||||
liCarac.find("input.xpCarac-view-ajout").val(carac.ajout)
|
||||
this.html.find("input.xpCarac-reste").val(this.xpData.reste)
|
||||
}
|
||||
|
||||
async appliquerSelection() {
|
||||
if (this.xpData.reste > 0) {
|
||||
ui.notifications.warn(`Il vous reste ${this.xpData.reste} points à répartir`)
|
||||
return
|
||||
}
|
||||
this.caracs.filter(c => c.ajout > 0).forEach(c => {
|
||||
const xpData = { caracName: c.label, xpCarac: c.ajout }
|
||||
this.actor._xpCarac(xpData)
|
||||
})
|
||||
await super.close()
|
||||
}
|
||||
|
||||
async close() { }
|
||||
|
||||
_getHeaderButtons() { return [] }
|
||||
}
|
@ -8,7 +8,7 @@ const LATEST_USED_JOURNAL_ID = "chronologie-dernier-journal";
|
||||
|
||||
export class DialogChronologie extends Dialog {
|
||||
|
||||
static init() {
|
||||
static initSettings() {
|
||||
game.settings.register(SYSTEM_RDD, LATEST_USED_JOURNAL_ID, {
|
||||
name: "Dernier article de journal utilisé pour enregistrer la chronologie",
|
||||
scope: "client",
|
||||
@ -25,23 +25,13 @@ export class DialogChronologie extends Dialog {
|
||||
journalId: game.settings.get(SYSTEM_RDD, LATEST_USED_JOURNAL_ID),
|
||||
journaux: game.journal.filter(it => it.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)),
|
||||
timestamp: game.system.rdd.calendrier.timestamp,
|
||||
dateReel: DialogChronologie.getCurrentDateTime()
|
||||
dateReel: game.system.rdd.calendrier.dateReel()
|
||||
};
|
||||
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-chronologie.html", dialogData);
|
||||
const dialog = new DialogChronologie(html, dialogData);
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
static getCurrentDateTime() {
|
||||
return new Date().toLocaleString("sv-SE", {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit"
|
||||
}).replace(" ", "T");
|
||||
}
|
||||
|
||||
constructor(html, dialogData) {
|
||||
const options = {
|
||||
classes: ["DialogChronologie"],
|
||||
|
@ -14,7 +14,7 @@ export class DialogCreateSigneDraconique extends Dialog {
|
||||
.map(actor => ({
|
||||
id: actor.id,
|
||||
name: actor.name,
|
||||
selected: true
|
||||
selected: false
|
||||
}))
|
||||
};
|
||||
|
||||
@ -24,7 +24,7 @@ export class DialogCreateSigneDraconique extends Dialog {
|
||||
}
|
||||
|
||||
constructor(dialogData, html) {
|
||||
let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 500, height: 650, 'z-index': 99999 };
|
||||
let options = { classes: ["DialogCreateSigneDraconiqueActors"], width: 500, height: 650, 'z-index': 99999 };
|
||||
let conf = {
|
||||
title: "Créer un signe",
|
||||
content: html,
|
||||
@ -48,10 +48,10 @@ export class DialogCreateSigneDraconique extends Dialog {
|
||||
async _createSigneForActor(actor, signe) {
|
||||
actor.createEmbeddedDocuments("Item", [signe]);
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(actor.name),
|
||||
whisper: ChatUtility.getOwners(actor),
|
||||
content: await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html", {
|
||||
signe: signe,
|
||||
alias: actor.name
|
||||
alias: actor.getAlias()
|
||||
})
|
||||
});
|
||||
}
|
||||
@ -111,7 +111,7 @@ export class DialogCreateSigneDraconique extends Dialog {
|
||||
|
||||
onSelectTmr(event) {
|
||||
const tmrName = this.html.find(event.currentTarget)?.data("tmr-name");
|
||||
const onTmr = this.tmrs.find(it => it.name == tmrName);
|
||||
const onTmr = this.dialogData.tmrs.find(it => it.name == tmrName);
|
||||
if (onTmr){
|
||||
onTmr.selected = event.currentTarget.checked;
|
||||
}
|
||||
|
@ -1,88 +1,79 @@
|
||||
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, onActionItem) {
|
||||
const min = DialogFabriquerPotion.nombreBrinsMinimum(item);
|
||||
if (item.system.quantite < min) {
|
||||
ui.notifications.warn(`Vous avez ${item.system.quantite} brins de ${item.name}, il en faut au moins ${min} pour faire une potion!`);
|
||||
return;
|
||||
static async create(actor, item) {
|
||||
const brinsMinimum = DialogFabriquerPotion.nombreBrinsMinimum(item)
|
||||
if (item.system.quantite < brinsMinimum) {
|
||||
ui.notifications.warn(`Vous avez ${item.system.quantite} brins de ${item.name}, il en faut au moins ${brinsMinimum} pour faire une potion!`)
|
||||
return
|
||||
}
|
||||
let potionData = DialogFabriquerPotion.prepareData(actor, item);
|
||||
const potionData = DialogFabriquerPotion.prepareData(item, brinsMinimum)
|
||||
const options = { classes: ["dialogfabriquerpotion"], width: 600, height: 160, 'z-index': 99999 }
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-fabriquer-potion-base.html', potionData)
|
||||
|
||||
const html = await renderTemplate( 'systems/foundryvtt-reve-de-dragon/templates/dialog-fabriquer-potion-base.html', potionData);
|
||||
|
||||
let options = { classes: ["dialogfabriquerpotion"], width: 600, height: 160, 'z-index': 99999 };
|
||||
new DialogFabriquerPotion(actor, potionData, onActionItem, html, options).render(true);
|
||||
new DialogFabriquerPotion(actor, potionData, html, options).render(true)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static prepareData(actor, item) {
|
||||
let potionData = duplicate(item)
|
||||
potionData.nbBrinsSelect = RdDUtility.buildListOptions(
|
||||
DialogFabriquerPotion.nombreBrinsMinimum(item),
|
||||
DialogFabriquerPotion.nombreBrinsOptimal(item));
|
||||
potionData.nbBrins = Math.min(potionData.system.quantite, DialogFabriquerPotion.nombreBrinsOptimal(potionData));
|
||||
potionData.herbebonus = item.system.niveau;
|
||||
potionData.buttonName = "Fabriquer";
|
||||
return potionData;
|
||||
static prepareData(item, brinsMinimum) {
|
||||
const brinsOptimal = DialogFabriquerPotion.nombreBrinsOptimal(item)
|
||||
return foundry.utils.mergeObject(foundry.utils.duplicate(item), {
|
||||
nbBrinsSelect: RdDUtility.buildListOptions(brinsMinimum, brinsOptimal),
|
||||
nbBrins: Math.min(item.system.quantite, brinsOptimal),
|
||||
herbebonus: item.system.niveau
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, potionData, onActionItem, html, options) {
|
||||
constructor(actor, potionData, html, options) {
|
||||
const conf = {
|
||||
title: `Fabriquer une potion de ${potionData.system.categorie}`,
|
||||
content: html,
|
||||
default: 'fabriquer',
|
||||
buttons: {
|
||||
'fabriquer': {
|
||||
label: potionData.buttonName, callback: it => this.onFabriquer()
|
||||
}
|
||||
'fabriquer': { label: "Fabriquer", callback: it => this.onFabriquer() }
|
||||
}
|
||||
};
|
||||
}
|
||||
super(conf, options)
|
||||
|
||||
super(conf, options);
|
||||
|
||||
this.actor = actor;
|
||||
this.potionData = potionData;
|
||||
this.onActionItem = onActionItem;
|
||||
this.actor = actor
|
||||
this.potionData = potionData
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
super.activateListeners(html)
|
||||
this.html = html
|
||||
this.html.find("[name='nbBrins']").change(event => {
|
||||
this.potionData.nbBrins = Misc.toInt(event.currentTarget.value);
|
||||
const brinsManquants = Math.max(0, DialogFabriquerPotion.nombreBrinsOptimal(this.potionData) - this.potionData.nbBrins);
|
||||
this.potionData.nbBrins = Misc.toInt(event.currentTarget.value)
|
||||
const brinsManquants = Math.max(0, DialogFabriquerPotion.nombreBrinsOptimal(this.potionData) - this.potionData.nbBrins)
|
||||
this.potionData.herbebonus = Math.max(0, this.potionData.system.niveau - brinsManquants)
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async onFabriquer() {
|
||||
await this.html.find("[name='nbBrins']").change();
|
||||
await this.actor.fabriquerPotion(this.potionData);
|
||||
this.close();
|
||||
await this.onActionItem()
|
||||
await this.html.find("[name='nbBrins']").change()
|
||||
await this.actor.fabriquerPotion(this.potionData)
|
||||
this.close()
|
||||
}
|
||||
|
||||
static nombreBrinsMinimum(herbeData) {
|
||||
switch (herbeData.system.categorie ?? '') {
|
||||
case "Soin": return 1 + Math.max(0, 12 - 2 * herbeData.system.niveau);
|
||||
case "Repos": return 1 + Math.max(0, 7 - 2 * herbeData.system.niveau);
|
||||
case "Soin": return 1 + Math.max(0, 12 - 2 * herbeData.system.niveau)
|
||||
case "Repos": return 1 + Math.max(0, 7 - 2 * herbeData.system.niveau)
|
||||
}
|
||||
return 1;
|
||||
return 1
|
||||
}
|
||||
|
||||
static nombreBrinsOptimal(herbeData) {
|
||||
switch (herbeData.system.categorie ?? '') {
|
||||
case "Soin": return 12 - herbeData.system.niveau;
|
||||
case "Repos": return 7 - herbeData.system.niveau;
|
||||
case "Soin": return 12 - herbeData.system.niveau
|
||||
case "Repos": return 7 - herbeData.system.niveau
|
||||
}
|
||||
return 1;
|
||||
return 1
|
||||
}
|
||||
}
|
@ -47,7 +47,7 @@ export class DialogConsommer extends Dialog {
|
||||
/* -------------------------------------------- */
|
||||
static prepareData(actor, item) {
|
||||
let consommerData = {
|
||||
item: duplicate(item),
|
||||
item: foundry.utils.duplicate(item),
|
||||
cuisine: actor.getCompetence('cuisine'),
|
||||
choix: {
|
||||
doses: 1,
|
||||
|
@ -1,37 +0,0 @@
|
||||
|
||||
export class DialogSelectTarget extends Dialog {
|
||||
constructor(html, onSelectTarget, targets) {
|
||||
const options = {
|
||||
classes: ["rdd-dialog-select-target"],
|
||||
width: 'fit-content',
|
||||
height: 'fit-content',
|
||||
'max-height': 600,
|
||||
'z-index': 99999
|
||||
};
|
||||
const conf = {
|
||||
title: "Choisir une cible",
|
||||
content: html,
|
||||
buttons: {}
|
||||
};
|
||||
super(conf, options);
|
||||
this.onSelectTarget = onSelectTarget;
|
||||
this.targets = targets;
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.html.find("li.select-target").click((event) => {
|
||||
this.targetSelected(this.html.find(event.currentTarget)?.data("token-id"));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
targetSelected(tokenId) {
|
||||
const target = this.targets.find(it => it.id == tokenId);
|
||||
this.close();
|
||||
if (target) {
|
||||
this.onSelectTarget(target);
|
||||
}
|
||||
}
|
||||
}
|
45
module/dialog-select.js
Normal file
@ -0,0 +1,45 @@
|
||||
|
||||
export class DialogSelect extends Dialog {
|
||||
static extractIdNameImg(it) { return { id: it.id, name: it.name, img: it.img } }
|
||||
|
||||
static async select(selectionData, onSelectChoice) {
|
||||
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-select.html", selectionData)
|
||||
|
||||
const dialogData = {
|
||||
title: selectionData.title ?? selectionData.label,
|
||||
content: html,
|
||||
buttons: {}
|
||||
}
|
||||
|
||||
const dialogOptions = {
|
||||
classes: ["rdd-dialog-select"],
|
||||
width: 'fit-content',
|
||||
height: 'fit-content',
|
||||
'max-height': 600,
|
||||
'z-index': 99999
|
||||
}
|
||||
new DialogSelect(dialogData, dialogOptions, selectionData, onSelectChoice).render(true)
|
||||
}
|
||||
|
||||
constructor(dialogData, dialogOptions, selectionData, onSelectChoice) {
|
||||
super(dialogData, dialogOptions)
|
||||
this.selectionData = selectionData
|
||||
this.onSelectChoice = onSelectChoice
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html)
|
||||
this.html = html
|
||||
this.html.find("li.select-choice").click(event =>
|
||||
this.choiceSelected(this.html.find(event.currentTarget)?.data("id"))
|
||||
)
|
||||
}
|
||||
|
||||
choiceSelected(selectedId) {
|
||||
const selected = this.selectionData.list.find(it => it.id == selectedId)
|
||||
this.close()
|
||||
if (selected) {
|
||||
this.onSelectChoice(selected)
|
||||
}
|
||||
}
|
||||
}
|
@ -7,20 +7,18 @@ import { RdDUtility } from "./rdd-utility.js";
|
||||
*/
|
||||
export class DialogValidationEncaissement extends Dialog {
|
||||
|
||||
static async validerEncaissement(actor, rollData, armure, show, onEncaisser) {
|
||||
let encaissement = await RdDUtility.jetEncaissement(rollData, armure, { showDice: HIDE_DICE });
|
||||
static async validerEncaissement(actor, rollData, armure, onEncaisser) {
|
||||
const encaissement = await RdDUtility.jetEncaissement(actor, rollData, armure, { showDice: HIDE_DICE });
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-validation-encaissement.html', {
|
||||
actor: actor,
|
||||
rollData: rollData,
|
||||
encaissement: encaissement,
|
||||
show: show
|
||||
encaissement: encaissement
|
||||
});
|
||||
const dialog = new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, show, onEncaisser);
|
||||
dialog.render(true);
|
||||
new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, onEncaisser).render(true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(html, actor, rollData, armure, encaissement, show, onEncaisser) {
|
||||
constructor(html, actor, rollData, armure, encaissement, onEncaisser) {
|
||||
// Common conf
|
||||
let buttons = {
|
||||
"valider": { label: "Valider", callback: html => this.onValider() },
|
||||
@ -47,7 +45,6 @@ export class DialogValidationEncaissement extends Dialog {
|
||||
this.rollData = rollData;
|
||||
this.armure = armure;
|
||||
this.encaissement = encaissement;
|
||||
this.show = show;
|
||||
this.onEncaisser = onEncaisser;
|
||||
this.forceDiceResult = {total: encaissement.roll.result };
|
||||
}
|
||||
@ -58,14 +55,14 @@ export class DialogValidationEncaissement extends Dialog {
|
||||
this.html = html;
|
||||
this.html.find('input.encaissement-roll-result').keyup(async event => {
|
||||
this.forceDiceResult.total = event.currentTarget.value;
|
||||
this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
|
||||
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
|
||||
this.html.find('label.encaissement-total').text(this.encaissement.total);
|
||||
this.html.find('label.encaissement-blessure').text(this.encaissement.blessures)
|
||||
});
|
||||
}
|
||||
|
||||
async onValider() {
|
||||
this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
|
||||
this.onEncaisser(this.encaissement, this.show)
|
||||
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
|
||||
this.onEncaisser(this.encaissement)
|
||||
}
|
||||
}
|
||||
|
177
module/enchantement/dialog-enchanter.js
Normal file
@ -0,0 +1,177 @@
|
||||
import { ITEM_TYPES } from "../constants.js"
|
||||
import { RdDItemSort } from "../item-sort.js"
|
||||
import { Misc } from "../misc.js"
|
||||
|
||||
export const ACTION_ITEM_ENCHANTER = {
|
||||
code: 'item-enchanter', label: 'Enchanter', icon: it => 'fa-solid fa-sparkles',
|
||||
filter: it => game.user.isGM || DialogEnchanter.isEnchantable(it),
|
||||
optionsFilter: options => options.editable,
|
||||
action: (item, actor) => DialogEnchanter.enchanter(item)
|
||||
}
|
||||
|
||||
export class DialogEnchanter extends Dialog {
|
||||
|
||||
static isEnchantable(item) {
|
||||
if (!item.isEnchantementPossible) {
|
||||
return false
|
||||
}
|
||||
if (game.user.isGM) {
|
||||
return true
|
||||
}
|
||||
if (item.system.prpermanent) {
|
||||
return false
|
||||
}
|
||||
if (!item.parent?.isHautRevant()) {
|
||||
return false
|
||||
}
|
||||
return RdDItemSort.lancements(RdDItemSort.findEnchantement(item.parent)) > 0
|
||||
|| RdDItemSort.lancements(RdDItemSort.findPurification(item.parent)) > 0
|
||||
|| RdDItemSort.lancements(RdDItemSort.findPermanence(item.parent)) > 0
|
||||
}
|
||||
|
||||
static dateEnchantement() {
|
||||
return game.system.rdd.calendrier.getTimestamp().debutJournee().indexDate
|
||||
}
|
||||
|
||||
static async enchanter(item) {
|
||||
const actor = item.parent
|
||||
const sorts = {
|
||||
enchantement: RdDItemSort.findEnchantement(actor),
|
||||
purification: RdDItemSort.findPurification(actor),
|
||||
permanence: RdDItemSort.findPermanence(actor)
|
||||
}
|
||||
const nouveauxpr = (sorts.enchantement?.system.lancements ?? []).map(it => it.reve)
|
||||
const purification = (sorts.purification?.system.lancements ?? []).find(it => true)
|
||||
const permanence = (sorts.permanence?.system.lancements ?? []).find(it => true)
|
||||
|
||||
const enchanter = {
|
||||
type: item.type == ITEM_TYPES.potion ? 'potion' : Misc.typeName('Item', item.type),
|
||||
actor: actor,
|
||||
item: item,
|
||||
reve: item.system.pr,
|
||||
sorts: sorts,
|
||||
nouveauxpr: nouveauxpr,
|
||||
purification: purification != undefined,
|
||||
permanence: permanence != undefined,
|
||||
options: { isGM: game.user.isGM }
|
||||
}
|
||||
if (!item.isEnchantementPossible) {
|
||||
ui.notifications.info("Seuls les liquides et les gemmes sont enchantables")
|
||||
return
|
||||
}
|
||||
if (item.system.prpermanent) {
|
||||
ui.notifications.info(`La ${enchanter.type} est permanente`)
|
||||
return
|
||||
}
|
||||
if (!game.user.isGM) {
|
||||
if (!(actor?.isPersonnage() || actor?.isHautRevant())) {
|
||||
ui.notifications.info(`Seul un haut rêvant peut enchanter une ${enchanter.type}`)
|
||||
return
|
||||
}
|
||||
if (item.system.quantite != 1) {
|
||||
ui.notifications.info(`Impossible d'enchanter ${item.system.quantite} ${enchanter.type}s ${item.system.quantite > 1 ? 'en une seule fois' : ''}`)
|
||||
return
|
||||
}
|
||||
if (!(nouveauxpr.length > 0 || purification || permanence)) {
|
||||
ui.notifications.info("Le haut-rêvant n'a lancé de rituel d'enchantement")
|
||||
return
|
||||
}
|
||||
if (item.system.magique && item.system.purifie && !purification && !permanence) {
|
||||
ui.notifications.info(`La ${enchanter.type} est déjà enchantée et doit être purifiée`)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/enchantement/dialog-enchanter.hbs`, enchanter)
|
||||
const dialog = new DialogEnchanter(enchanter, html)
|
||||
dialog.render(true)
|
||||
}
|
||||
|
||||
constructor(enchanter, html) {
|
||||
let options = { classes: ["dialog-enchanter"], width: 400, height: 'fit-content', 'z-index': 99999 }
|
||||
let conf = {
|
||||
title: `Enchanter une ${enchanter.type}`,
|
||||
content: html,
|
||||
default: "enchanter",
|
||||
buttons: {
|
||||
"enchanter": { label: "Enchanter", callback: it => this.onEnchanter() }
|
||||
}
|
||||
};
|
||||
super(conf, options)
|
||||
this.html = html
|
||||
this.enchanter = enchanter
|
||||
this.item = enchanter.item
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html)
|
||||
this.html = html
|
||||
this.html.find("input.enchantement").change(event => this.$onSelectEnchantement(event))
|
||||
this.html.find("input.reve").change(event => this.$onForceReve(event))
|
||||
}
|
||||
|
||||
$onSelectEnchantement(event) {
|
||||
const addReve = $(event.currentTarget).data('reve')
|
||||
this.enchanter.idx = $(event.currentTarget).data('idx')
|
||||
this.enchanter.reve = this.item.system.pr + Number(addReve)
|
||||
this.html.find("input.reve").val(this.enchanter.reve)
|
||||
for (let idx = 0; idx < this.enchanter.nouveauxpr.length; idx++) {
|
||||
if (idx != this.enchanter.idx) {
|
||||
this.html.find(`.enchantement[data-idx='${idx}']`).prop("checked", false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$onForceReve(event) {
|
||||
const newReve = Number(event.currentTarget.value)
|
||||
if (this.enchanter.reve != newReve) {
|
||||
this.enchanter.idx = undefined
|
||||
}
|
||||
this.enchanter.reve = newReve
|
||||
}
|
||||
|
||||
async onEnchanter() {
|
||||
foundry.utils.mergeObject(this.enchanter,
|
||||
{
|
||||
rendrepurifie: this.html.find("input.rendrepurifie").prop("checked"),
|
||||
rendrepermanent: this.html.find("input.rendrepermanent").prop("checked"),
|
||||
addreve: this.enchanter.reve != this.item.system.pr
|
||||
},
|
||||
{ inplace: true })
|
||||
const item = this.enchanter.item
|
||||
const actor = this.enchanter.actor
|
||||
|
||||
if (this.enchanter.reve == 0) {
|
||||
await item.update({
|
||||
'system.pr': 0,
|
||||
'system.magique': false,
|
||||
'system.purifie': false,
|
||||
'system.prpermanent': false,
|
||||
'system.prdate': 0
|
||||
})
|
||||
}
|
||||
else {
|
||||
const isPurifiee = this.enchanter.addreve
|
||||
? (this.enchanter.rendrepurifie && (item.item.system.pr == 0 ? true : item.system.purifie))
|
||||
: (this.enchanter.rendrepurifie || item.system.purifie)
|
||||
await item.update({
|
||||
'system.pr': this.enchanter.reve,
|
||||
'system.magique': true,
|
||||
'system.purifie': isPurifiee,
|
||||
'system.prpermanent': item.system.prpermanent || this.enchanter.rendrepermanent,
|
||||
'system.prdate': DialogEnchanter.dateEnchantement()
|
||||
})
|
||||
if (actor) {
|
||||
if (this.enchanter.rendrepurifie) {
|
||||
await RdDItemSort.changeLancementsSort(this.enchanter.sorts.purification, it => it.slice(1));
|
||||
}
|
||||
if (this.enchanter.rendrepermanent) {
|
||||
await RdDItemSort.changeLancementsSort(this.enchanter.sorts.permanence, it => it.slice(1));
|
||||
}
|
||||
if (this.enchanter.addreve && this.enchanter.idx != undefined) {
|
||||
await RdDItemSort.changeLancementsSort(RdDItemSort.findEnchantement(actor), it => it.toSpliced(this.enchanter.idx, 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ import { CompendiumTableHelpers, CompendiumTable, SystemCompendiums } from "./se
|
||||
const COMPENDIUMS_RECHERCHE = 'compendiums-recherche';
|
||||
|
||||
export class Environnement {
|
||||
static init() {
|
||||
static initSettings() {
|
||||
game.settings.register(SYSTEM_RDD, COMPENDIUMS_RECHERCHE, {
|
||||
name: COMPENDIUMS_RECHERCHE,
|
||||
default: [
|
||||
|
@ -24,7 +24,7 @@ export class Grammar {
|
||||
}
|
||||
|
||||
static includesLowerCaseNoAccent(value, content) {
|
||||
return Grammar.toLowerCaseNoAccent(value).includes(Grammar.toLowerCaseNoAccent(content));
|
||||
return Grammar.toLowerCaseNoAccent(value)?.includes(Grammar.toLowerCaseNoAccent(content));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -1,9 +1,12 @@
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"
|
||||
import { ITEM_TYPES } from "./constants.js";
|
||||
import { BASE_CORPS_A_CORPS } from "./item/base-items.js";
|
||||
import { RdDCombatManager } from "./rdd-combat.js";
|
||||
|
||||
const nomCategorieParade = {
|
||||
"sans-armes": "Sans arme",
|
||||
"armes-naturelles": "Sans arme",
|
||||
"armes-naturelles": "Armes naturelles",
|
||||
"hast": "Armes d'hast",
|
||||
"batons": "Bâtons",
|
||||
"boucliers": "Boucliers",
|
||||
@ -19,17 +22,33 @@ const nomCategorieParade = {
|
||||
export class RdDItemArme extends Item {
|
||||
|
||||
static isArme(item) {
|
||||
return (item.type == 'competencecreature' && item.system.iscombat) || item.type == 'arme';
|
||||
return item.type == ITEM_TYPES.arme || RdDItemCompetenceCreature.getCategorieAttaque(item);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getArme(arme) {
|
||||
switch (arme ? arme.type : '') {
|
||||
case 'arme': return arme;
|
||||
case 'competencecreature':
|
||||
return RdDItemCompetenceCreature.armeNaturelle(arme);
|
||||
case ITEM_TYPES.arme: return arme;
|
||||
case ITEM_TYPES.competencecreature:
|
||||
return RdDItemCompetenceCreature.armeCreature(arme);
|
||||
}
|
||||
return RdDItemArme.mainsNues();
|
||||
return RdDItemArme.corpsACorps();
|
||||
}
|
||||
|
||||
static getCompetenceArme(arme, maniement) {
|
||||
switch (arme.type) {
|
||||
case ITEM_TYPES.competencecreature:
|
||||
return arme.name
|
||||
case ITEM_TYPES.arme:
|
||||
switch (maniement) {
|
||||
case 'competence': return arme.system.competence;
|
||||
case 'unemain': return RdDItemArme.competence1Mains(arme);
|
||||
case 'deuxmains': return RdDItemArme.competence2Mains(arme);
|
||||
case 'tir': return arme.system.tir;
|
||||
case 'lancer': return arme.system.lancer;
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
static computeNiveauArmes(armes, competences) {
|
||||
@ -39,8 +58,8 @@ export class RdDItemArme extends Item {
|
||||
}
|
||||
|
||||
static niveauCompetenceArme(arme, competences) {
|
||||
const compArme = competences.find(it => it.name == arme.system.competence);
|
||||
return compArme?.system.niveau ?? -8;
|
||||
const compArme = competences.find(it => Grammar.equalsInsensitive(it.name, arme.system.competence))
|
||||
return compArme?.system.niveau ?? -8
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -64,37 +83,59 @@ export class RdDItemArme extends Item {
|
||||
/* -------------------------------------------- */
|
||||
static getCategorieParade(armeData) {
|
||||
if (armeData.system.categorie_parade) {
|
||||
return armeData.system.categorie_parade;
|
||||
return armeData.system.categorie_parade
|
||||
}
|
||||
// pour compatibilité avec des personnages existants
|
||||
if (armeData.type == 'competencecreature' || armeData.system.categorie == 'creature') {
|
||||
return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : '');
|
||||
if (armeData.type == ITEM_TYPES.competencecreature || armeData.system.categorie == 'creature') {
|
||||
return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : '')
|
||||
}
|
||||
if (!armeData.type.match(/arme|competencecreature/)) {
|
||||
return '';
|
||||
return ''
|
||||
}
|
||||
if (armeData.system.competence == undefined) {
|
||||
return 'competencecreature';
|
||||
return ITEM_TYPES.competencecreature;
|
||||
}
|
||||
let compname = armeData.system.competence.toLowerCase();
|
||||
if (compname.match(/^(dague de jet|javelot|fouet|arc|arbalête|fronde|hache de jet|fléau)$/)) return '';
|
||||
if (compname.match(/^(dague de jet|javelot|fouet|arc|arbalête|fronde|hache de jet|fléau)$/)) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (compname.match('hache')) return 'haches';
|
||||
if (compname.match('hast')) return 'hast';
|
||||
if (compname.match('lance')) return 'lances';
|
||||
if (compname.match('bouclier')) return 'boucliers';
|
||||
if (compname.match('masse')) return 'masses';
|
||||
if (compname.match('hache')) return 'haches'
|
||||
if (compname.match('hast')) return 'hast'
|
||||
if (compname.match('lance')) return 'lances'
|
||||
if (compname.match('bouclier')) return 'boucliers'
|
||||
if (compname.match('masse')) return 'masses'
|
||||
if (compname.match('epée') || compname.match('épée')) {
|
||||
if (armeData.name.toLowerCase().match(/(gnome)/))
|
||||
return 'epees-courtes';
|
||||
return 'epees-courtes'
|
||||
if (armeData.name.toLowerCase().match(/((e|é)pée dragone|esparlongue|demi-dragonne)/))
|
||||
return 'epees-longues';
|
||||
return 'epees-lourdes';
|
||||
return 'epees-longues'
|
||||
return 'epees-lourdes'
|
||||
}
|
||||
if (compname.match('dague')) {
|
||||
return 'dagues';
|
||||
return 'dagues'
|
||||
}
|
||||
return 'sans-armes'
|
||||
}
|
||||
|
||||
static defenseArmeParade(armeAttaque, armeParade) {
|
||||
const defCategory = RdDItemArme.getCategorieParade(armeParade)
|
||||
if (defCategory == 'bouclier') {
|
||||
return 'norm'
|
||||
}
|
||||
if (armeAttaque.system.competence.toLowerCase().match(/(fléau)/)) {
|
||||
return ''
|
||||
}
|
||||
if (armeParade.system.tir) {
|
||||
return ''
|
||||
}
|
||||
const attCategory = RdDItemArme.getCategorieParade(armeAttaque)
|
||||
switch (attCategory) {
|
||||
case 'armes-naturelles': case 'sans-armes':
|
||||
return defCategory == 'sans-armes' ? 'norm' : ''
|
||||
default:
|
||||
return RdDItemArme.needParadeSignificative(armeAttaque, armeParade) ? 'sign' : 'norm'
|
||||
}
|
||||
return 'sans-armes';
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -103,8 +144,8 @@ export class RdDItemArme extends Item {
|
||||
return false;
|
||||
}
|
||||
// categories d'armes à la parade (cf. page 115 )
|
||||
let attCategory = RdDItemArme.getCategorieParade(armeAttaque);
|
||||
let defCategory = RdDItemArme.getCategorieParade(armeParade);
|
||||
const attCategory = RdDItemArme.getCategorieParade(armeAttaque)
|
||||
const defCategory = RdDItemArme.getCategorieParade(armeParade)
|
||||
// bouclier et mêmes catégorie: peuvent se parer sans difficulté
|
||||
if (defCategory == 'boucliers') {
|
||||
return false;
|
||||
@ -131,48 +172,80 @@ export class RdDItemArme extends Item {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static armeUneOuDeuxMains(armeData, aUneMain) {
|
||||
if (armeData && !armeData.system.cac) {
|
||||
armeData.system.unemain = armeData.system.unemain || !armeData.system.deuxmains;
|
||||
const uneOuDeuxMains = armeData.system.unemain && armeData.system.deuxmains;
|
||||
const containsSlash = !Number.isInteger(armeData.system.dommages) && armeData.system.dommages.includes("/");
|
||||
if (containsSlash) { // Sanity check
|
||||
armeData = duplicate(armeData);
|
||||
|
||||
const tableauDegats = armeData.system.dommages.split("/");
|
||||
if (aUneMain)
|
||||
armeData.system.dommagesReels = Number(tableauDegats[0]);
|
||||
else // 2 mains
|
||||
armeData.system.dommagesReels = Number(tableauDegats[1]);
|
||||
}
|
||||
else {
|
||||
armeData.system.dommagesReels = Number(armeData.system.dommages);
|
||||
}
|
||||
|
||||
if (uneOuDeuxMains != containsSlash) {
|
||||
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + armeData.name + " ne sont pas corrects (ie sous la forme X/Y)");
|
||||
}
|
||||
static dommagesReels(arme, maniement) {
|
||||
switch (maniement) {
|
||||
case 'tir':
|
||||
case 'lancer':
|
||||
case 'competence':
|
||||
return Number(arme.system.dommages)
|
||||
}
|
||||
return armeData;
|
||||
if (arme.system.unemain && arme.system.deuxmains) {
|
||||
const containsSlash = !Number.isInteger(arme.system.dommages) && arme.system.dommages.includes("/")
|
||||
if (!containsSlash) {
|
||||
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + arme.name + " ne sont pas corrects (ie sous la forme X/Y)");
|
||||
return Number(arme.system.dommages)
|
||||
}
|
||||
const tableauDegats = arme.system.dommages.split("/");
|
||||
return Number(tableauDegats[maniement == 'unemain' ? 0 : 1])
|
||||
}
|
||||
return Number(arme.system.dommages);
|
||||
}
|
||||
|
||||
static isArmeUtilisable(arme) {
|
||||
return arme.type == 'arme' && arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0);
|
||||
/* -------------------------------------------- */
|
||||
static armeUneOuDeuxMains(arme, aUneMain) {
|
||||
if (arme && !arme.system.cac) {
|
||||
arme = foundry.utils.duplicate(arme);
|
||||
arme.system.dommagesReels = RdDItemArme.dommagesReels(arme, aUneMain ? 'unemain' : 'deuxmains')
|
||||
}
|
||||
return arme;
|
||||
}
|
||||
|
||||
static ajoutCorpsACorps(armes, competences, carac) {
|
||||
let corpsACorps = competences.find(it => it.name == 'Corps à corps') ?? { system: { niveau: -6 } };
|
||||
let init = RdDCombatManager.calculInitiative(corpsACorps.system.niveau, carac['melee'].value);
|
||||
armes.push(RdDItemArme.mainsNues({ niveau: corpsACorps.system.niveau, initiative: init }));
|
||||
armes.push(RdDItemArme.empoignade({ niveau: corpsACorps.system.niveau, initiative: init }));
|
||||
static competence1Mains(arme) {
|
||||
return arme.system.competence.replace(" 2 mains", " 1 main");
|
||||
}
|
||||
|
||||
static corpsACorps(mainsNuesActor) {
|
||||
const corpsACorps = {
|
||||
static competence2Mains(arme) {
|
||||
return arme.system.competence.replace(" 1 main", " 2 mains");
|
||||
}
|
||||
|
||||
static isUtilisable(arme) {
|
||||
switch (arme.type) {
|
||||
case ITEM_TYPES.arme: return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0)
|
||||
case ITEM_TYPES.competencecreature: return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static isAttaque(arme) {
|
||||
switch (arme.type) {
|
||||
case ITEM_TYPES.arme:
|
||||
return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0)
|
||||
case ITEM_TYPES.competencecreature:
|
||||
return arme.system.iscombat && RdDItemCompetenceCreature.isAttaque(item)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static isParade(arme) {
|
||||
switch (arme.type) {
|
||||
case ITEM_TYPES.arme:
|
||||
return arme.system.equipe && arme.system.resistance > 0 && true/* TODO: regarder la categorie d'arme?*/
|
||||
case ITEM_TYPES.competencecreature:
|
||||
return arme.system.iscombat && RdDItemCompetenceCreature.isParade(arme)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static corpsACorps(actor) {
|
||||
let competence = actor?.getCompetenceCorpsACorps() ?? BASE_CORPS_A_CORPS
|
||||
let melee = actor ? actor.system.carac['melee'].value : 0
|
||||
return {
|
||||
_id: competence.id,
|
||||
name: 'Corps à corps',
|
||||
img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp',
|
||||
type: ITEM_TYPES.arme,
|
||||
img: competence.img,
|
||||
system: {
|
||||
initiative: RdDCombatManager.calculInitiative(competence.system.niveau, melee),
|
||||
equipe: true,
|
||||
rapide: true,
|
||||
force: 0,
|
||||
@ -180,23 +253,23 @@ export class RdDItemArme extends Item {
|
||||
dommagesReels: 0,
|
||||
mortalite: 'non-mortel',
|
||||
competence: 'Corps à corps',
|
||||
resistance: 1,
|
||||
baseInit: 4,
|
||||
cac: 'pugilat',
|
||||
deuxmains: true,
|
||||
categorie_parade: 'sans-armes'
|
||||
}
|
||||
};
|
||||
mergeObject(corpsACorps.system, mainsNuesActor ?? {}, { overwrite: false });
|
||||
return corpsACorps;
|
||||
}
|
||||
}
|
||||
|
||||
static mainsNues(mainsNuesActor) {
|
||||
const mainsNues = RdDItemArme.corpsACorps(mainsNuesActor)
|
||||
static mainsNues(actor) {
|
||||
const mainsNues = RdDItemArme.corpsACorps(actor)
|
||||
mainsNues.name = 'Mains nues'
|
||||
mainsNues.system.cac = 'pugilat'
|
||||
mainsNues.system.baseInit = 4
|
||||
return mainsNues;
|
||||
}
|
||||
|
||||
static empoignade(mainsNuesActor) {
|
||||
const empoignade = RdDItemArme.corpsACorps(mainsNuesActor)
|
||||
|
||||
static empoignade(actor) {
|
||||
const empoignade = RdDItemArme.corpsACorps(actor)
|
||||
empoignade.name = 'Empoignade'
|
||||
empoignade.system.cac = 'empoignade'
|
||||
empoignade.system.baseInit = 3
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { RdDItem } from "./item.js";
|
||||
import { SANS_COMPETENCE } from "./item/base-items.js";
|
||||
import { Misc } from "./misc.js";
|
||||
|
||||
const competenceTroncs = [["Esquive", "Dague", "Corps à corps"],
|
||||
@ -8,27 +10,27 @@ const xp_par_niveau = [5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20,
|
||||
const niveau_max = xp_par_niveau.length - 10;
|
||||
/* -------------------------------------------- */
|
||||
const limitesArchetypes = [
|
||||
{ "niveau": 0, "nombreMax": 100, "reste": 100 },
|
||||
{ "niveau": 1, "nombreMax": 10, "reste": 10 },
|
||||
{ "niveau": 2, "nombreMax": 9, "reste": 9 },
|
||||
{ "niveau": 3, "nombreMax": 8, "reste": 8 },
|
||||
{ "niveau": 4, "nombreMax": 7, "reste": 7 },
|
||||
{ "niveau": 5, "nombreMax": 6, "reste": 6 },
|
||||
{ "niveau": 6, "nombreMax": 5, "reste": 5 },
|
||||
{ "niveau": 7, "nombreMax": 4, "reste": 4 },
|
||||
{ "niveau": 8, "nombreMax": 3, "reste": 3 },
|
||||
{ "niveau": 9, "nombreMax": 2, "reste": 2 },
|
||||
{ "niveau": 10, "nombreMax": 1, "reste": 1 },
|
||||
{ "niveau": 11, "nombreMax": 1, "reste": 1 }
|
||||
{ niveau: 0, nombreMax: 100 },
|
||||
{ niveau: 1, nombreMax: 10 },
|
||||
{ niveau: 2, nombreMax: 9 },
|
||||
{ niveau: 3, nombreMax: 8 },
|
||||
{ niveau: 4, nombreMax: 7 },
|
||||
{ niveau: 5, nombreMax: 6 },
|
||||
{ niveau: 6, nombreMax: 5 },
|
||||
{ niveau: 7, nombreMax: 4 },
|
||||
{ niveau: 8, nombreMax: 3 },
|
||||
{ niveau: 9, nombreMax: 2 },
|
||||
{ niveau: 10, nombreMax: 1 },
|
||||
{ niveau: 11, nombreMax: 1 },
|
||||
];
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const categorieCompetences = {
|
||||
export const CATEGORIES_COMPETENCES = {
|
||||
"generale": { base: -4, label: "Générales" },
|
||||
"particuliere": { base: -8, label: "Particulières" },
|
||||
"specialisee": { base: -11, label: "Spécialisées" },
|
||||
"connaissance": { base: -11, label: "Connaissances" },
|
||||
"draconic": { base: -11, label: "Draconics" },
|
||||
"draconic": { base: -11, label: "Draconic" },
|
||||
"melee": { base: -6, label: "Mêlée" },
|
||||
"tir": { base: -8, label: "Tir" },
|
||||
"lancer": { base: -8, label: "Lancer" }
|
||||
@ -48,17 +50,15 @@ function _buildCumulXP() {
|
||||
const competence_xp_cumul = _buildCumulXP();
|
||||
|
||||
export class RdDItemCompetence extends Item {
|
||||
/* -------------------------------------------- */
|
||||
static getCategorieCompetences() {
|
||||
return categorieCompetences;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static getNiveauBase(category) {
|
||||
return categorieCompetences[category].base;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static getLabelCategorie(category) {
|
||||
return categorieCompetences[category].label;
|
||||
return CATEGORIES_COMPETENCES[category].label;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
/* -------------------------------------------- */
|
||||
static getNiveauBase(category, itemType) {
|
||||
let categories = RdDItem.getCategories(itemType)
|
||||
return categories[category]?.base ?? 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -79,10 +79,9 @@ export class RdDItemCompetence extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isCompetenceArme(competence) {
|
||||
if (competence.isCompetence()) {
|
||||
if (competence.isCompetence() && !competence.isCorpsACorps() && !competence.isEsquive()) {
|
||||
switch (competence.system.categorie) {
|
||||
case 'melee':
|
||||
return !Grammar.toLowerCaseNoAccent(competence.name).includes('esquive');
|
||||
case 'tir':
|
||||
case 'lancer':
|
||||
return true;
|
||||
@ -93,10 +92,10 @@ export class RdDItemCompetence extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isArmeUneMain(competence) {
|
||||
return RdDItemCompetence.isCompetenceArme(competence) && competence.name.toLowerCase().includes("1 main");
|
||||
return competence.isCompetenceArme() && competence.name.toLowerCase().includes("1 main");
|
||||
}
|
||||
static isArme2Main(competence) {
|
||||
return RdDItemCompetence.isCompetenceArme(competence) && competence.name.toLowerCase().includes("2 main");
|
||||
return competence.isCompetenceArme() && competence.name.toLowerCase().includes("2 main");
|
||||
}
|
||||
|
||||
static isThanatos(competence) {
|
||||
@ -139,7 +138,7 @@ export class RdDItemCompetence extends Item {
|
||||
/* -------------------------------------------- */
|
||||
static computeEconomieXPTronc(competences) {
|
||||
return competenceTroncs.map(
|
||||
list => list.map(name => RdDItemCompetence.findCompetence(competences, name))
|
||||
list => list.map(name => RdDItemCompetence.findCompetence(competences, name, { onMessage: message => { } }))
|
||||
// calcul du coût xp jusqu'au niveau 0 maximum
|
||||
.map(it => RdDItemCompetence.computeDeltaXP(it?.system.base ?? -11, Math.min(it?.system.niveau ?? -11, 0)))
|
||||
.sort(Misc.ascending())
|
||||
@ -192,7 +191,7 @@ export class RdDItemCompetence extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isNiveauBase(item) {
|
||||
return Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie);
|
||||
return item.system.niveau == undefined || Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie, item.type);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -200,31 +199,17 @@ export class RdDItemCompetence extends Item {
|
||||
if (idOrName == undefined || idOrName == "") {
|
||||
return RdDItemCompetence.sansCompetence();
|
||||
}
|
||||
options = mergeObject(options, { preFilter: it => it.isCompetence(), description: 'compétence' }, { overwrite: false });
|
||||
options = foundry.utils.mergeObject(options, { preFilter: it => it.isCompetence(), description: 'compétence' }, { overwrite: false, inplace: false });
|
||||
return RdDItemCompetence.findFirstItem(list, idOrName, options);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static findCompetences(list, name) {
|
||||
return Misc.findAllLike(name, list, { filter: it => it.isCompetence(), description: 'compétence' });
|
||||
static findCompetences(list, name, options = {}) {
|
||||
options = foundry.utils.mergeObject(options, { preFilter: it => it.isCompetence(), description: 'compétence' }, { overwrite: false, inplace: false });
|
||||
return Misc.findAllLike(name, list, options);
|
||||
}
|
||||
|
||||
static sansCompetence() {
|
||||
return {
|
||||
name: "Sans compétence",
|
||||
type: "competence",
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp",
|
||||
system: {
|
||||
niveau: 0,
|
||||
default_diffLibre: 0,
|
||||
base: 0,
|
||||
categorie: "Aucune",
|
||||
description: "",
|
||||
descriptionmj: "",
|
||||
defaut_carac: "",
|
||||
}
|
||||
};
|
||||
}
|
||||
static sansCompetence() { return SANS_COMPETENCE }
|
||||
|
||||
static findFirstItem(list, idOrName, options) {
|
||||
return list.find(it => it.id == idOrName && options.preFilter(it))
|
||||
@ -258,20 +243,25 @@ export class RdDItemCompetence extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static computeResumeArchetype(competences) {
|
||||
const computed = duplicate(limitesArchetypes);
|
||||
const computed = foundry.utils.duplicate(limitesArchetypes);
|
||||
computed.forEach(it => { it.nombre = 0; it.reste = it.nombreMax; });
|
||||
|
||||
competences.map(it => Math.max(0, it.system.niveau_archetype))
|
||||
.filter(n => n > 0)
|
||||
.forEach(n => {
|
||||
computed[n] = computed[n] ?? { niveau: n, nombreMax: 0, reste: 0 };
|
||||
computed[n].reste = computed[n].reste - 1;
|
||||
computed[n] = computed[n] ?? { niveau: n, nombreMax: 0, reste: 0, nombre: 0 };
|
||||
computed[n].reste--;
|
||||
computed[n].nombre++;
|
||||
|
||||
});
|
||||
return computed.filter(it => it.reste > 0 && it.niveau > 0);
|
||||
return computed.filter(it => it.niveau > 0);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static triVisible(competences) {
|
||||
return competences.filter(it => !it.system.isHidden)
|
||||
.sort((a, b) => RdDItemCompetence.compare(a, b))
|
||||
return competences
|
||||
? competences.filter(it => !it.system.isHidden).sort((a, b) => RdDItemCompetence.compare(a, b))
|
||||
: []
|
||||
}
|
||||
|
||||
static $positionTri(comp) {
|
||||
|
@ -1,53 +1,89 @@
|
||||
|
||||
import { ITEM_TYPES } from "./constants.js";
|
||||
import { RdDCombatManager } from "./rdd-combat.js";
|
||||
|
||||
export const CATEGORIES_COMPETENCES_CREATURES = {
|
||||
"generale": { base: 0, label: "Générale" },
|
||||
"naturelle": { base: 0, label: "Arme naturelle" },
|
||||
"melee": { base: 0, label: "Mêlée" },
|
||||
"parade": { base: 0, label: "Parade" },
|
||||
"tir": { base: 0, label: "Tir" },
|
||||
"lancer": { base: 0, label: "Lancer" },
|
||||
"possession": { base: 0, label: "Possession" },
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDItemCompetenceCreature extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static setRollDataCreature(rollData) {
|
||||
rollData.competence = rollData.competence
|
||||
rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.system.carac_value } }
|
||||
rollData.competence.system.defaut_carac = "carac_creature"
|
||||
rollData.competence.system.categorie = "creature"
|
||||
rollData.selectedCarac = rollData.carac.carac_creature
|
||||
if (rollData.competence.system.iscombat) {
|
||||
rollData.arme = RdDItemCompetenceCreature.armeNaturelle(rollData.competence);
|
||||
}
|
||||
rollData.selectedCarac = rollData.carac.carac_creature
|
||||
rollData.arme = RdDItemCompetenceCreature.armeCreature(rollData.competence);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static armeNaturelle(competencecreature) {
|
||||
if (RdDItemCompetenceCreature.isCompetenceAttaque(competencecreature)) {
|
||||
// si c'est un Item compétence: cloner pour ne pas modifier lma compétence
|
||||
let arme = (competencecreature instanceof Item) ? competencecreature.clone(): competencecreature;
|
||||
mergeObject(arme.system,
|
||||
{
|
||||
competence: arme.name,
|
||||
initiative: RdDCombatManager.calculInitiative(competencecreature.system.niveau, competencecreature.system.carac_value),
|
||||
niveau: competencecreature.system.niveau,
|
||||
equipe: true,
|
||||
resistance: 100,
|
||||
dommagesReels: arme.system.dommages,
|
||||
penetration: 0,
|
||||
force: 0,
|
||||
rapide: true,
|
||||
cac: competencecreature.system.isnaturelle ? "naturelle" : "",
|
||||
action: 'attaque'
|
||||
});
|
||||
return arme;
|
||||
static armeCreature(item) {
|
||||
const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(item)
|
||||
if (categorieAttaque != undefined) {
|
||||
// cloner pour ne pas modifier la compétence
|
||||
return foundry.utils.mergeObject(item, {
|
||||
action: item.isCompetencePossession() ? 'possession' : 'attaque',
|
||||
system: {
|
||||
competence: item.name,
|
||||
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
|
||||
niveau: item.system.niveau,
|
||||
initiative: RdDCombatManager.calculInitiative(item.system.niveau, item.system.carac_value),
|
||||
equipe: true,
|
||||
resistance: 100,
|
||||
dommagesReels: item.system.dommages,
|
||||
penetration: 0,
|
||||
force: 0,
|
||||
rapide: true,
|
||||
}
|
||||
}, { inplace: false, });
|
||||
}
|
||||
console.error("RdDItemCompetenceCreature.toActionArme(", competencecreature, ") : impossible de transformer l'Item en arme");
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isCompetenceAttaque(item) {
|
||||
return item.type == 'competencecreature' && item.system.iscombat;
|
||||
static isAttaque(item) {
|
||||
return RdDItemCompetenceCreature.getCategorieAttaque(item) != undefined
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isCompetenceParade(item) {
|
||||
return item.type == 'competencecreature' && item.system.categorie_parade !== "";
|
||||
|
||||
static getCategorieAttaque(item) {
|
||||
if (item.type == ITEM_TYPES.competencecreature) {
|
||||
switch (item.system.categorie) {
|
||||
case "melee":
|
||||
case "tir":
|
||||
case "lancer":
|
||||
case "naturelle":
|
||||
case "possession":
|
||||
return item.system.categorie
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
static isDommages(item) {
|
||||
if (item.type == ITEM_TYPES.competencecreature) {
|
||||
switch (item.system.categorie) {
|
||||
case "melee":
|
||||
case "tir":
|
||||
case "lancer":
|
||||
case "naturelle":
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static isParade(item) {
|
||||
if (item.type == ITEM_TYPES.competencecreature) {
|
||||
return item.system.categorie_parade || item.system.isparade
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Misc } from "./misc.js";
|
||||
import { LOG_HEAD } from "./constants.js";
|
||||
import { ITEM_TYPES, LOG_HEAD } from "./constants.js";
|
||||
|
||||
const MONNAIE_ETAIN = {
|
||||
name: "Denier (étain)", type: 'monnaie',
|
||||
@ -57,7 +57,7 @@ export class Monnaie {
|
||||
}
|
||||
|
||||
static creerDeniers(fortune) {
|
||||
const deniers = duplicate(MONNAIE_ETAIN);
|
||||
const deniers = foundry.utils.duplicate(MONNAIE_ETAIN);
|
||||
deniers.system.quantite = fortune;
|
||||
return deniers;
|
||||
}
|
||||
@ -70,18 +70,17 @@ export class Monnaie {
|
||||
}
|
||||
|
||||
static getFortune(monnaies) {
|
||||
return (monnaies??[])
|
||||
return (monnaies ?? [])
|
||||
.map(m => Number(m.system.cout) * Number(m.system.quantite))
|
||||
.reduce(Misc.sum(), 0);
|
||||
}
|
||||
|
||||
static async optimiserFortune(actor, fortune) {
|
||||
Monnaie.validerMonnaies(actor)
|
||||
let resteEnDeniers = Math.round(fortune * 100);
|
||||
let monnaies = actor.itemTypes['monnaie'];
|
||||
let updates = [];
|
||||
Monnaie.validerMonnaies(monnaies, actor);
|
||||
const updates = []
|
||||
|
||||
let parValeur = Misc.classifyFirst(monnaies, it => VALEUR_DENIERS(it.system.cout));
|
||||
const parValeur = Misc.classifyFirst(actor.itemTypes[ITEM_TYPES.monnaie], it => VALEUR_DENIERS(it.system.cout));
|
||||
for (let valeurDeniers of [1000, 100, 10, 1]) {
|
||||
const itemPiece = parValeur[valeurDeniers];
|
||||
if (itemPiece) {
|
||||
@ -102,8 +101,11 @@ export class Monnaie {
|
||||
}
|
||||
}
|
||||
|
||||
static validerMonnaies(monnaies, actor = undefined) {
|
||||
monnaies.filter(it => VALEUR_DENIERS(it.system.cout) == 0)
|
||||
static validerMonnaies(actor) {
|
||||
if (!actor) {
|
||||
return
|
||||
}
|
||||
actor.itemTypes[ITEM_TYPES.monnaie]?.filter(it => VALEUR_DENIERS(it.system.cout) == 0)
|
||||
.map(it => `La monnaie ${it.name} de l'acteur ${actor?.name ?? 'sélectionné'} a une valeur de 0!`)
|
||||
.forEach(message => {
|
||||
ui.notifications.warn(message);
|
||||
|
@ -1,16 +1,20 @@
|
||||
import { ACTOR_TYPES, ITEM_TYPES } from "./constants.js";
|
||||
import { RdDItemSort } from "./item-sort.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { RdDAlchimie } from "./rdd-alchimie.js";
|
||||
import { RdDItemCompetence } from "./item-competence.js";
|
||||
import { RdDHerbes } from "./rdd-herbes.js";
|
||||
import { RdDGemme } from "./rdd-gemme.js";
|
||||
import { HtmlUtility } from "./html-utility.js";
|
||||
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
|
||||
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
||||
import { SYSTEM_RDD } from "./constants.js";
|
||||
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
|
||||
import { SystemCompendiums } from "./settings/system-compendiums.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
import { RdDItem } from "./item.js";
|
||||
import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js";
|
||||
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
|
||||
import { ItemAction } from "./item/item-actions.js";
|
||||
import { RdDItemGemme } from "./item/gemme.js";
|
||||
|
||||
/**
|
||||
* Extend the basic ItemSheet for RdD specific items
|
||||
@ -23,8 +27,8 @@ export class RdDItemSheet extends ItemSheet {
|
||||
|
||||
static defaultTemplate(type) {
|
||||
return type ?
|
||||
`systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html` :
|
||||
"systems/foundryvtt-reve-de-dragon/templates/item-sheet.html";
|
||||
`systems/foundryvtt-reve-de-dragon/templates/item/${type}-sheet.hbs` :
|
||||
"systems/foundryvtt-reve-de-dragon/templates/item/item-sheet.hbs";
|
||||
}
|
||||
|
||||
static register(sheetClass) {
|
||||
@ -37,12 +41,12 @@ export class RdDItemSheet extends ItemSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: [SYSTEM_RDD, "sheet", "item"],
|
||||
template: RdDItemSheet.defaultTemplate(RdDItemSheet.ITEM_TYPE),
|
||||
width: 550,
|
||||
height: 550
|
||||
});
|
||||
}, { inplace: false });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -51,7 +55,8 @@ export class RdDItemSheet extends ItemSheet {
|
||||
}
|
||||
|
||||
get title() {
|
||||
return `${Misc.typeName('Item', this.item.type)}: ${this.item.name}`;
|
||||
const owner = (this.item.parent instanceof Actor) ? `(${this.item.parent.name})` : '';
|
||||
return `${Misc.typeName('Item', this.item.type)}: ${this.item.name} ${owner}`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -93,55 +98,56 @@ export class RdDItemSheet extends ItemSheet {
|
||||
name: this.item.name,
|
||||
system: this.item.system,
|
||||
actorId: this.actor?.id,
|
||||
description: await TextEditor.enrichHTML(this.item.system.description, { async: true }),
|
||||
descriptionmj: await TextEditor.enrichHTML(this.item.system.descriptionmj, { async: true }),
|
||||
description: await RdDTextEditor.enrichHTML(this.item.system.description, this.item),
|
||||
descriptionmj: await RdDTextEditor.enrichHTML(this.item.system.descriptionmj, this.item),
|
||||
isComestible: this.item.getUtilisationCuisine(),
|
||||
options: RdDSheetUtility.mergeDocumentRights(this.options, this.item, this.isEditable)
|
||||
options: RdDSheetUtility.mergeDocumentRights(this.options, this.item, this.isEditable),
|
||||
competences: await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage),
|
||||
categories: RdDItem.getCategories(this.item.type),
|
||||
}
|
||||
|
||||
const competences = await SystemCompendiums.getCompetences('personnage');
|
||||
formData.categorieCompetences = RdDItemCompetence.getCategorieCompetences()
|
||||
if (this.item.type == 'tache' || this.item.type == 'livre' || this.item.type == 'meditation' || this.item.type == 'oeuvre') {
|
||||
formData.caracList = duplicate(game.system.model.Actor.personnage.carac)
|
||||
formData.caracList["reve-actuel"] = duplicate(game.system.model.Actor.personnage.reve.reve)
|
||||
formData.competences = competences;
|
||||
if (this.item.type == ITEM_TYPES.competencecreature) {
|
||||
formData.isparade = RdDItemCompetenceCreature.isParade(this.item)
|
||||
formData.isdommages = RdDItemCompetenceCreature.isDommages(this.item)
|
||||
}
|
||||
if (this.item.type == 'arme') {
|
||||
formData.competences = competences.filter(it => RdDItemCompetence.isCompetenceArme(it))
|
||||
if (this.item.type == ITEM_TYPES.tache ||
|
||||
this.item.type == ITEM_TYPES.livre ||
|
||||
this.item.type == ITEM_TYPES.meditation ||
|
||||
this.item.type == ITEM_TYPES.oeuvre) {
|
||||
formData.caracList = foundry.utils.duplicate(game.model.Actor.personnage.carac)
|
||||
formData.caracList["reve-actuel"] = foundry.utils.duplicate(game.model.Actor.personnage.reve.reve)
|
||||
}
|
||||
if (['sort', 'sortreserve'].includes(this.item.type)) {
|
||||
formData.competences = competences.filter(it => RdDItemCompetence.isDraconic(it));
|
||||
if (this.item.type == ITEM_TYPES.arme) {
|
||||
formData.competences = formData.competences.filter(it => it.isCompetenceArme())
|
||||
}
|
||||
if (this.item.type == 'recettecuisine') {
|
||||
formData.ingredients = await TextEditor.enrichHTML(this.object.system.ingredients, { async: true })
|
||||
if (this.item.type == ITEM_TYPES.recettecuisine) {
|
||||
formData.ingredients = await RdDTextEditor.enrichHTML(this.item.system.ingredients, this.item)
|
||||
}
|
||||
if (this.item.type == 'extraitpoetique') {
|
||||
formData.extrait = await TextEditor.enrichHTML(this.object.system.extrait, { async: true })
|
||||
formData.texte = await TextEditor.enrichHTML(this.object.system.texte, { async: true })
|
||||
if (this.item.type == ITEM_TYPES.extraitpoetique) {
|
||||
formData.extrait = await RdDTextEditor.enrichHTML(this.item.system.extrait, this.item)
|
||||
formData.texte = await RdDTextEditor.enrichHTML(this.item.system.texte, this.item)
|
||||
}
|
||||
if (this.item.type == 'recettealchimique') {
|
||||
RdDAlchimie.processManipulation(this.item, this.actor && this.actor.id);
|
||||
formData.manipulation_update = await TextEditor.enrichHTML(this.object.system.manipulation_update, { async: true })
|
||||
formData.utilisation = await TextEditor.enrichHTML(this.object.system.utilisation, { async: true })
|
||||
formData.enchantement = await TextEditor.enrichHTML(this.object.system.enchantement, { async: true })
|
||||
formData.sureffet = await TextEditor.enrichHTML(this.object.system.sureffet, { async: true })
|
||||
if (this.item.type == ITEM_TYPES.recettealchimique) {
|
||||
formData.manipulation = await RdDTextEditor.enrichHTML(this.item.system.manipulation, this.item)
|
||||
formData.utilisation = await RdDTextEditor.enrichHTML(this.item.system.utilisation, this.item)
|
||||
formData.enchantement = await RdDTextEditor.enrichHTML(this.item.system.enchantement, this.item)
|
||||
formData.sureffet = await RdDTextEditor.enrichHTML(this.item.system.sureffet, this.item)
|
||||
}
|
||||
if (this.item.type == 'gemme') {
|
||||
formData.gemmeTypeList = RdDGemme.getGemmeTypeOptionList();
|
||||
RdDGemme.calculDataDerivees(this.item);
|
||||
|
||||
if (this.item.type == ITEM_TYPES.herbe) {
|
||||
if (formData.options.isOwned && ['Soin', 'Repos'].includes(formData.system.categorie)) {
|
||||
formData.isIngredientPotionBase = true;
|
||||
}
|
||||
}
|
||||
if (this.item.type == 'potion') {
|
||||
await RdDHerbes.addPotionFormData(formData);
|
||||
}
|
||||
if (formData.options.isOwned && this.item.type == 'herbe' && (formData.system.categorie == 'Soin' || formData.system.categorie == 'Repos')) {
|
||||
formData.isIngredientPotionBase = true;
|
||||
}
|
||||
if (this.item.type == 'sortreserve') {
|
||||
if (this.item.type == ITEM_TYPES.sortreserve) {
|
||||
const sortId = this.item.system.sortid;
|
||||
formData.competences = formData.competences.filter(it => RdDItemCompetence.isDraconic(it));
|
||||
formData.sort = formData.options.isOwned ? this.item.actor.items.get(sortId) : game.items.get(sortId);
|
||||
}
|
||||
formData.bonusCaseList = RdDItemSort.getBonusCaseList(formData, true);
|
||||
|
||||
if (this.item.type == ITEM_TYPES.sort) {
|
||||
formData.competences = formData.competences.filter(it => RdDItemCompetence.isDraconic(it));
|
||||
formData.bonusCaseList = RdDItemSort.getBonusCaseList(this.item);
|
||||
}
|
||||
return formData;
|
||||
}
|
||||
|
||||
@ -151,10 +157,10 @@ export class RdDItemSheet extends ItemSheet {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
|
||||
HtmlUtility.showControlWhen(this.html.find(".item-cout"), ReglesOptionelles.isUsing('afficher-prix-joueurs')
|
||||
HtmlUtility.showControlWhen(this.html.find(".item-cout"), ReglesOptionnelles.isUsing('afficher-prix-joueurs')
|
||||
|| game.user.isGM
|
||||
|| !this.item.isOwned);
|
||||
HtmlUtility.showControlWhen(this.html.find(".item-magique"), this.item.isMagique());
|
||||
HtmlUtility.showControlWhen(this.html.find(".item-magique"), this.item.isMagique);
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
@ -178,62 +184,57 @@ export class RdDItemSheet extends ItemSheet {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.html.find('.date-enchantement').change((event) => {
|
||||
const jour = Number(this.html.find('input.date-enchantement[name="enchantement.jour"]').val());
|
||||
const mois = RdDTimestamp.definition(this.html.find('select.date-enchantement[name="enchantement.mois"]').val());
|
||||
const indexDate = game.system.rdd.calendrier.getIndexFromDate(jour, mois.heure);
|
||||
this.item.update({ 'system.prdate': indexDate });
|
||||
console.warn(`Date d'enchantement modifiée ${jour}/${mois.heure}: ${indexDate}`)
|
||||
});
|
||||
this.html.find('.delete-bonus-case').click((event) => {
|
||||
this.supprimerBonusCase(event.currentTarget.attributes['data-deleteCoord'].value)
|
||||
})
|
||||
|
||||
this.html.find('.creer-tache-livre').click((event) => this._getEventActor(event).creerTacheDepuisLivre(this.item));
|
||||
this.html.find('.consommer-potion').click((event) => this._getEventActor(event).consommerPotion(this.item, this.getActionRenderItem()));
|
||||
this.html.find('.creer-potion-base').click((event) => this._getEventActor(event).dialogFabriquerPotion(this.item));
|
||||
this.html.find('.creer-potion-base').click((event) => this._getEventActor(event).fabriquerDecoctionHerbe(this.item))
|
||||
this.html.find('input[name="system.cacher_points_de_tache"]').change(async event => await this.item.update({ 'system.cacher_points_de_tache': event.currentTarget.checked }));
|
||||
|
||||
this.html.find('.alchimie-tache a').click((event) => {
|
||||
let actor = this._getEventActor(event);
|
||||
if (actor) {
|
||||
let recetteId = event.currentTarget.attributes['data-recette-id'].value;
|
||||
let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value;
|
||||
let tacheData = event.currentTarget.attributes['data-alchimie-data'].value;
|
||||
actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData);
|
||||
} else {
|
||||
ui.notifications.info("Impossible trouver un acteur pour réaliser cette tache Alchimique.");
|
||||
}
|
||||
});
|
||||
this.html.find('.roll-text').click(async event => await RdDTextEditor.rollText(event, this.actor))
|
||||
this.html.find('.chat-roll-text').click(async event => await RdDTextEditor.chatRollText(event))
|
||||
|
||||
if (this.actor) {
|
||||
this.html.find('.item-split').click(async event => RdDSheetUtility.splitItem(RdDSheetUtility.getItem(event, this.actor), this.actor, this.getActionRenderItem()));
|
||||
this.html.find('.item-edit').click(async event => RdDSheetUtility.getItem(event, this.actor)?.sheet.render(true));
|
||||
this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, RdDSheetUtility.getItem(event, this.actor)));
|
||||
this.html.find('.item-vendre').click(async event => RdDSheetUtility.getItem(event, this.actor)?.proposerVente());
|
||||
this.html.find('.item-montrer').click(async event => RdDSheetUtility.getItem(event, this.actor)?.postItemToChat());
|
||||
this.html.find('.item-action').click(async event => RdDSheetUtility.getItem(event, this.actor)?.actionPrincipale(this.actor, this.getActionRenderItem()));
|
||||
this.html.find('.actionItem').click(event => ItemAction.onActionItem(event, this.actor, this.options))
|
||||
|
||||
// TODO: utiliser un itemAction?
|
||||
this.html.find('.item-potion-consommer').click(event => this.itemActionConsommer(event))
|
||||
|
||||
this.html.find('.item-quantite-plus').click(async event => {
|
||||
await this.actor.itemQuantiteIncDec(RdDSheetUtility.getItemId(event), 1)
|
||||
this.render();
|
||||
});
|
||||
this.render()
|
||||
})
|
||||
this.html.find('.item-quantite-moins').click(async event => {
|
||||
await this.actor.itemQuantiteIncDec(RdDSheetUtility.getItemId(event), -1)
|
||||
this.render();
|
||||
});
|
||||
this.render()
|
||||
})
|
||||
}
|
||||
|
||||
const updateItemTimestamp = (path, timestamp) => this.item.update({ [path]: duplicate(timestamp) })
|
||||
const updateItemTimestamp = (path, timestamp) => this.item.update({ [path]: foundry.utils.duplicate(timestamp) })
|
||||
|
||||
RdDTimestamp.handleTimestampEditor(this.html, 'system.temporel.debut', updateItemTimestamp);
|
||||
RdDTimestamp.handleTimestampEditor(this.html, 'system.temporel.fin', updateItemTimestamp);
|
||||
}
|
||||
|
||||
getActionRenderItem() {
|
||||
return async () => {
|
||||
let item = this.item;
|
||||
while (item) {
|
||||
await item.sheet?.render()
|
||||
item = this.actor.getContenant(item)
|
||||
}
|
||||
itemActionDelete(event) {
|
||||
const item = RdDSheetUtility.getItem(event, this.actor)
|
||||
return RdDUtility.confirmActorItemDelete(item, this.actor)
|
||||
}
|
||||
|
||||
async itemActionConsommer(event) {
|
||||
const item = RdDSheetUtility.getItem(event, this.actor)
|
||||
if (item) {
|
||||
await actor.consommerPotion(item)
|
||||
await RdDSheetUtility.renderItemBranch(this.actor, item)
|
||||
}
|
||||
}
|
||||
|
||||
async itemActionSplit(event) {
|
||||
const item = RdDSheetUtility.getItem(event, this.actor)
|
||||
if (item) {
|
||||
await RdDSheetUtility.splitItem(item, this.actor)
|
||||
await RdDSheetUtility.renderItemBranch(this.actor, item)
|
||||
}
|
||||
}
|
||||
|
||||
@ -249,22 +250,73 @@ export class RdDItemSheet extends ItemSheet {
|
||||
event.preventDefault();
|
||||
|
||||
if (this.item.isCompetence()) {
|
||||
let level = RdDItemCompetence.getNiveauBase(event.currentTarget.value);
|
||||
const categorie = event.currentTarget.value;
|
||||
const level = RdDItemCompetence.getNiveauBase(categorie, this.item.type);
|
||||
this.item.system.base = level;
|
||||
this.html.find('[name="system.base"]').val(level);
|
||||
}
|
||||
}
|
||||
|
||||
async supprimerBonusCase(deleteCoord) {
|
||||
if (this.item.type == ITEM_TYPES.sort) {
|
||||
const oldList = RdDItemSort.getBonusCaseList(this.item)
|
||||
const newList = oldList.filter(it => it.case != deleteCoord);
|
||||
if (newList.length != oldList.length) {
|
||||
await this.item.update({
|
||||
'system.bonuscase': RdDItemSort.bonuscasesToString(newList)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
_updateObject(event, formData) {
|
||||
if (this.item.type == 'sort') {
|
||||
// Données de bonus de cases ?
|
||||
formData['system.bonuscase'] = RdDItemSort.buildBonuscaseFromArrays(formData.bonusValue, formData.caseValue);
|
||||
switch (this.item.type) {
|
||||
case ITEM_TYPES.sort:
|
||||
formData['system.bonuscase'] = RdDItemSort.bonuscasesToString(RdDItemSheet._listCaseTmr(
|
||||
formData.caseTmrCoord,
|
||||
formData.caseTmrBonus,
|
||||
formData.caseTmrAdd
|
||||
))
|
||||
break
|
||||
case ITEM_TYPES.competence:
|
||||
formData['system.niveau'] = formData['system.niveau'] ?? formData['system.base']
|
||||
break
|
||||
}
|
||||
|
||||
return this.item.update(formData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/**
|
||||
* reconstruit les bonus de cases
|
||||
* @param {*} caseTmrCoord tableau des coordonées
|
||||
* @param {*} caseTmrBonus tableau des bonus
|
||||
* @param {*} caseTmrAdd case à ajouter
|
||||
* @returns list d'objets {coord, bonus}
|
||||
*/
|
||||
static _listCaseTmr(caseTmrCoord, caseTmrBonus, caseTmrAdd) {
|
||||
const listCaseTmrCoord = caseTmrCoord == undefined ? [] : Array.isArray(caseTmrCoord) ? caseTmrCoord : [caseTmrCoord]
|
||||
const listCaseTmrBonus = caseTmrBonus == undefined ? [] : Array.isArray(caseTmrBonus) ? caseTmrBonus : [caseTmrBonus]
|
||||
if (caseTmrAdd != undefined && caseTmrAdd != '' && TMRUtility.verifyTMRCoord(caseTmrAdd) && !listCaseTmrCoord.includes(caseTmrAdd)) {
|
||||
listCaseTmrCoord.push(TMRUtility.getTMR(caseTmrAdd).coord)
|
||||
listCaseTmrBonus.push(1)
|
||||
}
|
||||
|
||||
const list = [];
|
||||
const caseChecked = {};
|
||||
for (let i = 0; i < listCaseTmrBonus.length && i < listCaseTmrCoord.length; i++) {
|
||||
const coord = listCaseTmrCoord[i] == FLEUVE_COORD ? FLEUVE_COORD : (listCaseTmrCoord[i]?.toUpperCase() ?? 'A1')
|
||||
const bonus = listCaseTmrBonus[i] ?? 0
|
||||
if (TMRUtility.verifyTMRCoord(coord) && bonus >= 0 && !caseChecked[coord]) {
|
||||
caseChecked[coord] = coord
|
||||
list.push({ case: coord, bonus: bonus })
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _onDragStart(event) {
|
||||
}
|
||||
|
@ -1,8 +1,89 @@
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { RdDItemCompetence } from "./item-competence.js";
|
||||
import { ITEM_TYPES } from "./constants.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { TMRUtility } from "./tmr-utility.js";
|
||||
import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js";
|
||||
|
||||
export const VOIES_DRACONIC = [
|
||||
{ code: 'O', label: "Voie d'Oniros", short: 'Oniros', ordre: 'a' },
|
||||
{ code: 'H', label: "Voie d'Hypnos", short: 'Hypnos', ordre: 'b' },
|
||||
{ code: 'N', label: "Voie de Narcos", short: 'Narcos', ordre: 'c' },
|
||||
{ code: 'T', label: "Voie de Thanatos", short: 'Thanatos', ordre: 'd' },
|
||||
{ code: 'O/H/N/T', label: "Oniros/Hypnos/Narcos/Thanatos", short: 'O/H/N/T', ordre: 'e' },
|
||||
{ code: 'O/H/N', label: "Oniros/Hypnos/Narcos", short: "O/H/N", ordre: 'f' }
|
||||
]
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDItemSort extends Item {
|
||||
static preloadHandlebars() {
|
||||
Handlebars.registerHelper('itemSort-spaceIfText', val => RdDItemSort.addSpaceToNonNumeric(val))
|
||||
Handlebars.registerHelper('itemSort-codeDraconic', voie => RdDItemSort.getCode(voie))
|
||||
Handlebars.registerHelper('itemSort-shortDraconic', voie => RdDItemSort.getShortVoie(voie))
|
||||
}
|
||||
|
||||
static addSpaceToNonNumeric(value) {
|
||||
return Number.isNumeric(value) || ['-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].includes(String(value).charAt[0]) ? value : ' ' + RdDItemSort.toVar(value)
|
||||
}
|
||||
|
||||
static lancements(sort) { return sort?.system.lancements.length ?? 0 }
|
||||
|
||||
static findEnchantement(actor) { return RdDItemSort.findSort(actor, 'Enchantement', ['Narcos', 'N']) }
|
||||
static findPermanence(actor) { return RdDItemSort.findSort(actor, 'Permanence', ['Narcos', 'N']) }
|
||||
static findPurification(actor) { return RdDItemSort.findSort(actor, 'Purification', ['Narcos', 'N']) }
|
||||
|
||||
static findSort(actor, name, draconics) {
|
||||
return actor.itemTypes[ITEM_TYPES.sort].find(it => Grammar.includesLowerCaseNoAccent(it.name, name)
|
||||
&& (draconics == undefined || draconics.includes(it.system.draconic)))
|
||||
}
|
||||
static async changeLancementsSort(sort, changement) {
|
||||
await sort?.update({ 'system.lancements': changement(sort.system.lancements) });
|
||||
}
|
||||
|
||||
static toVar(value) {
|
||||
return value ? value.replace('variable', 'var') : ''
|
||||
}
|
||||
|
||||
static getDraconicsSort(competencesDraconic, sort) {
|
||||
// se baser sur la voie du sort?
|
||||
switch (Grammar.toLowerCaseNoAccent(sort.name)) {
|
||||
case "lecture d'aura":
|
||||
case "detection d'aura":
|
||||
return competencesDraconic;
|
||||
case "annulation de magie":
|
||||
return competencesDraconic.filter(it => !RdDItemCompetence.isThanatos(it));
|
||||
}
|
||||
const voies = sort.system.draconic.split('/')
|
||||
return voies.map(voie => RdDItemCompetence.getVoieDraconic(competencesDraconic, voie))
|
||||
}
|
||||
|
||||
static getOrdreCode(code) {
|
||||
return (VOIES_DRACONIC.find(it => it.code == code)?.ordre ?? '?')
|
||||
}
|
||||
|
||||
static getCodeVoie(voie) {
|
||||
return VOIES_DRACONIC.find(it => [it.code, it.short, it.label].includes(voie))?.code ?? '?'
|
||||
}
|
||||
|
||||
static getShortVoie(voie) {
|
||||
return VOIES_DRACONIC.find(it => [it.code, it.short, it.label].includes(voie))?.short ?? voie
|
||||
}
|
||||
|
||||
static getCode(sort, codeVoies = ['O', 'H', 'N', 'T']) {
|
||||
switch (Grammar.toLowerCaseNoAccent(sort.name)) {
|
||||
case "lecture d'aura":
|
||||
case "detection d'aura":
|
||||
return RdDItemSort.$voiesConnues('O/H/N/T', codeVoies)
|
||||
case "annulation de magie":
|
||||
return RdDItemSort.$voiesConnues('O/H/N', codeVoies)
|
||||
}
|
||||
return RdDItemSort.getCodeVoie(sort.system.draconic)
|
||||
}
|
||||
|
||||
static $voiesConnues(voiesSort, voies) {
|
||||
const codes = voies.filter(it => voiesSort.includes(it))
|
||||
.sort(Misc.ascending(it => RdDItemSort.getOrdreCode(it)))
|
||||
return Misc.join(codes ?? [''], '/');
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isDifficulteVariable(sort) {
|
||||
@ -29,86 +110,59 @@ export class RdDItemSort extends Item {
|
||||
return variable;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static buildBonusCaseList(bonuscase, newCase) {
|
||||
const list = RdDItemSort._bonuscaseStringToList(bonuscase)
|
||||
if (newCase) {
|
||||
return list.concat({ case: "Nouvelle", bonus: 0 });
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne une liste de bonus/case pour un item-sheet
|
||||
* @param {} item
|
||||
*/
|
||||
static getBonusCaseList(item, newCase = false) {
|
||||
static getBonusCaseList(item) {
|
||||
// Gestion spéciale case bonus
|
||||
if (item.type == 'sort') {
|
||||
return RdDItemSort.buildBonusCaseList(item.system.bonuscase, newCase);
|
||||
if (item.type == ITEM_TYPES.sort) {
|
||||
return RdDItemSort.stringToBonuscases(item.system.bonuscase)
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** Met à jour les données de formulaire
|
||||
* si static des bonus de cases sont présents
|
||||
* */
|
||||
static buildBonuscaseFromArrays(bonuses, coords) {
|
||||
if (bonuses) {
|
||||
const list = [];
|
||||
const caseCheck = {};
|
||||
for (let i = 0; i < bonuses.length && i < coords.length; i++) {
|
||||
const coord = coords[i] == 'Fleuve' ? 'Fleuve' : (coords[i]?.toUpperCase() ?? 'A1');
|
||||
const bonus = bonuses[i] || 0;
|
||||
if (TMRUtility.verifyTMRCoord(coord) && bonus > 0 && caseCheck[coord] == undefined) {
|
||||
caseCheck[coord] = bonus;
|
||||
list.push({ case: coord, bonus: bonus });
|
||||
}
|
||||
}
|
||||
return RdDItemSort._bonuscaseListToString(list);
|
||||
}
|
||||
return undefined;
|
||||
return [];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static incrementBonusCase(actor, sort, coord) {
|
||||
if (TMRUtility.getTMR(coord).type == "fleuve") {
|
||||
coord = 'Fleuve';
|
||||
if (TMRUtility.isFleuve(coord)) {
|
||||
coord = FLEUVE_COORD;
|
||||
}
|
||||
let list = RdDItemSort.stringToBonuscases(sort.system.bonuscase);
|
||||
const existing = list.find(it => it.case == coord)
|
||||
const bonus = Number(existing?.bonus ?? 0) + 1
|
||||
if (existing) {
|
||||
existing.bonus = bonus
|
||||
}
|
||||
else {
|
||||
list.push({ case: coord, bonus: 1 })
|
||||
}
|
||||
const list = RdDItemSort.buildBonusCaseList(sort.system.bonuscase, false);
|
||||
const bonus = Number(list.find(it => it.case == coord)?.bonus ?? 0);
|
||||
const modified = { case: coord, bonus: bonus + 1 };
|
||||
|
||||
const bonuscase = RdDItemSort._bonuscaseListToString(
|
||||
list.filter(it => it.case != coord).concat(modified)
|
||||
);
|
||||
|
||||
// Sauvegarde/update
|
||||
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': bonuscase }]);
|
||||
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': RdDItemSort.bonuscasesToString(list) }]);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getCaseBonus(sort, coord) {
|
||||
const isFleuve = TMRUtility.getTMR(coord).type == "fleuve";
|
||||
|
||||
let bc = RdDItemSort.buildBonusCaseList(sort.system.bonuscase, false)
|
||||
.filter(it => it.case == coord || (isFleuve && it.case == 'Fleuve'))
|
||||
.find(it => true)
|
||||
const search = TMRUtility.isFleuve(coord)
|
||||
? it => it.case == 'Fleuve'
|
||||
: it => it.case == coord;
|
||||
const bc = RdDItemSort.stringToBonuscases(sort.system.bonuscase)
|
||||
.find(search)
|
||||
return Number(bc?.bonus ?? 0);
|
||||
}
|
||||
|
||||
static _bonuscaseListToString(list) {
|
||||
static bonuscasesToString(list) {
|
||||
return list.map(it => `${it.case}:${it.bonus}`)
|
||||
.sort(Misc.ascending())
|
||||
.join(',');
|
||||
}
|
||||
static _bonuscaseStringToList(bonuscase) {
|
||||
return (bonuscase ?? '').split(',').map(it => {
|
||||
const b = it.split(':');
|
||||
return { case: b[0], bonus: b[1] };
|
||||
});
|
||||
}
|
||||
|
||||
static stringToBonuscases(bonuscase) {
|
||||
if (bonuscase == undefined || bonuscase == '') {
|
||||
return []
|
||||
}
|
||||
return bonuscase.split(',')
|
||||
.map(it => it.split(':'))
|
||||
.map(it => { return { case: it[0], bonus: it[1] } });
|
||||
}
|
||||
}
|
388
module/item.js
@ -1,124 +1,87 @@
|
||||
import { DialogItemVente } from "./dialog-item-vente.js";
|
||||
import { ITEM_TYPES } from "./constants.js";
|
||||
import { DialogItemVente } from "./achat-vente/dialog-item-vente.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { RdDHerbes } from "./rdd-herbes.js";
|
||||
import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { SystemCompendiums } from "./settings/system-compendiums.js";
|
||||
import { RdDRaretes } from "./item/raretes.js";
|
||||
import { CATEGORIES_COMPETENCES } from "./item-competence.js";
|
||||
import { CATEGORIES_COMPETENCES_CREATURES } from "./item-competencecreature.js";
|
||||
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE } from "./item/base-items.js";
|
||||
import { ITEM_ACTIONS, DEFAULT_ACTIONS, COMMON_ACTIONS } from "./item/item-actions.js";
|
||||
|
||||
export const TYPES = {
|
||||
competence: 'competence',
|
||||
competencecreature: 'competencecreature',
|
||||
arme: 'arme',
|
||||
armure: 'armure',
|
||||
conteneur: 'conteneur',
|
||||
sort: 'sort',
|
||||
herbe: 'herbe',
|
||||
faune: 'faune',
|
||||
ingredient: 'ingredient',
|
||||
livre: 'livre',
|
||||
potion: 'potion',
|
||||
rencontre: 'rencontre',
|
||||
queue: 'queue',
|
||||
ombre: 'ombre',
|
||||
souffle: 'souffle',
|
||||
tete: 'tete',
|
||||
meditation: 'meditation',
|
||||
recettealchimique: 'recettealchimique',
|
||||
chant: 'chant',
|
||||
danse: 'danse',
|
||||
jeu: 'jeu',
|
||||
recettecuisine: 'recettecuisine',
|
||||
musique: 'musique',
|
||||
maladie: 'maladie',
|
||||
poison: 'poison',
|
||||
oeuvre: 'oeuvre',
|
||||
nourritureboisson: 'nourritureboisson',
|
||||
service: 'service',
|
||||
signedraconique: 'signedraconique',
|
||||
gemme: 'gemme',
|
||||
possession: 'possession',
|
||||
sortreserve: 'sortreserve',
|
||||
extraitpoetique: 'extraitpoetique',
|
||||
tarot: 'tarot',
|
||||
empoignade: 'empoignade'
|
||||
}
|
||||
const typesInventaireMateriel = [
|
||||
TYPES.arme,
|
||||
TYPES.armure,
|
||||
TYPES.conteneur,
|
||||
TYPES.faune,
|
||||
TYPES.gemme,
|
||||
TYPES.herbe,
|
||||
TYPES.plante,
|
||||
TYPES.ingredient,
|
||||
TYPES.livre,
|
||||
TYPES.monnaie,
|
||||
TYPES.munition,
|
||||
TYPES.nourritureboisson,
|
||||
TYPES.objet,
|
||||
TYPES.potion,
|
||||
ITEM_TYPES.arme,
|
||||
ITEM_TYPES.armure,
|
||||
ITEM_TYPES.conteneur,
|
||||
ITEM_TYPES.faune,
|
||||
ITEM_TYPES.gemme,
|
||||
ITEM_TYPES.herbe,
|
||||
ITEM_TYPES.plante,
|
||||
ITEM_TYPES.ingredient,
|
||||
ITEM_TYPES.livre,
|
||||
ITEM_TYPES.monnaie,
|
||||
ITEM_TYPES.munition,
|
||||
ITEM_TYPES.nourritureboisson,
|
||||
ITEM_TYPES.objet,
|
||||
ITEM_TYPES.potion,
|
||||
]
|
||||
const typesInventaire = {
|
||||
materiel: typesInventaireMateriel,
|
||||
all: ['service'].concat(typesInventaireMateriel),
|
||||
}
|
||||
|
||||
const typesObjetsOeuvres = [TYPES.oeuvre, TYPES.recettecuisine, TYPES.musique, TYPES.chant, TYPES.danse, TYPES.jeu]
|
||||
const typesObjetsDraconiques = [TYPES.queue, TYPES.ombre, TYPES.souffle, TYPES.tete, TYPES.signedraconique, TYPES.sortreserve, TYPES.rencontre]
|
||||
const typesObjetsConnaissance = [TYPES.meditation, TYPES.recettealchimique, TYPES.sort]
|
||||
const typesObjetsEffet = [TYPES.possession, TYPES.poison, TYPES.maladie, TYPES.blessure]
|
||||
const typesObjetsCompetence = [TYPES.competence, TYPES.competencecreature]
|
||||
const typesObjetsTemporels = [TYPES.blessure, TYPES.poison, TYPES.maladie, TYPES.queue, TYPES.ombre, TYPES.souffle, TYPES.signedraconique, TYPES.rencontre]
|
||||
const typesObjetsEquipable = [TYPES.arme, TYPES.armure, TYPES.objet];
|
||||
const typesObjetsOeuvres = [ITEM_TYPES.oeuvre, ITEM_TYPES.recettecuisine, ITEM_TYPES.musique, ITEM_TYPES.chant, ITEM_TYPES.danse, ITEM_TYPES.jeu]
|
||||
const typesObjetsDraconiques = [ITEM_TYPES.queue, ITEM_TYPES.ombre, ITEM_TYPES.souffle, ITEM_TYPES.tete, ITEM_TYPES.signedraconique, ITEM_TYPES.sortreserve, ITEM_TYPES.rencontre]
|
||||
const typesObjetsConnaissance = [ITEM_TYPES.meditation, ITEM_TYPES.recettealchimique, ITEM_TYPES.sort]
|
||||
const typesObjetsEffet = [ITEM_TYPES.possession, ITEM_TYPES.poison, ITEM_TYPES.maladie, ITEM_TYPES.blessure]
|
||||
const typesObjetsCompetence = [ITEM_TYPES.competence, ITEM_TYPES.competencecreature]
|
||||
const typesObjetsTemporels = [ITEM_TYPES.blessure, ITEM_TYPES.poison, ITEM_TYPES.maladie, ITEM_TYPES.queue, ITEM_TYPES.ombre, ITEM_TYPES.souffle, ITEM_TYPES.signedraconique, ITEM_TYPES.rencontre]
|
||||
const typesObjetsEquipable = [ITEM_TYPES.arme, ITEM_TYPES.armure, ITEM_TYPES.objet];
|
||||
const typesEnvironnement = typesInventaireMateriel;
|
||||
const encBrin = 0.00005; // un brin = 1 décigramme = 1/10g = 1/10000kg = 1/20000 enc
|
||||
const encPepin = 0.0007; /* un pépin de gemme = 1/10 cm3 = 1/1000 l = 3.5/1000 kg = 7/2000 kg = 7/1000 enc
|
||||
densité 3.5 (~2.3 à 4, parfois plus) -- https://www.juwelo.fr/guide-des-pierres/faits-et-chiffres/
|
||||
*/
|
||||
|
||||
export const defaultItemImg = {
|
||||
competence: "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp",
|
||||
competencecreature: "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp",
|
||||
arme: "systems/foundryvtt-reve-de-dragon/icons/armes_armures/epee_gnome.webp",
|
||||
armure: "systems/foundryvtt-reve-de-dragon/icons/armes_armures/armure_plaques.webp",
|
||||
conteneur: "systems/foundryvtt-reve-de-dragon/icons/objets/sac_a_dos.webp",
|
||||
sort: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp",
|
||||
herbe: "systems/foundryvtt-reve-de-dragon/icons/botanique/Endorlotte.webp",
|
||||
faune: "systems/foundryvtt-reve-de-dragon/icons/faune/rongeur.webp",
|
||||
ingredient: "systems/foundryvtt-reve-de-dragon/icons/objets/sable_poudre.webp",
|
||||
livre: "systems/foundryvtt-reve-de-dragon/icons/objets/livre.webp",
|
||||
potion: "systems/foundryvtt-reve-de-dragon/icons/objets/liqueur_de_bagdol.webp",
|
||||
rencontre: "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp",
|
||||
queue: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp",
|
||||
ombre: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp",
|
||||
souffle: "systems/foundryvtt-reve-de-dragon/icons/souffle_dragon.webp",
|
||||
tete: "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp",
|
||||
meditation: "systems/foundryvtt-reve-de-dragon/icons/meditations_ecrits/meditation_alchimie.webp",
|
||||
recettealchimique: "systems/foundryvtt-reve-de-dragon/icons/competence_alchimie.webp",
|
||||
chant: "systems/foundryvtt-reve-de-dragon/icons/arts/chant_0.webp",
|
||||
competence: "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp",
|
||||
competencecreature: "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp",
|
||||
conteneur: "systems/foundryvtt-reve-de-dragon/icons/objets/sac_a_dos.webp",
|
||||
danse: "systems/foundryvtt-reve-de-dragon/icons/arts/danse_0.webp",
|
||||
empoignade: "systems/foundryvtt-reve-de-dragon/icons/empoignade.webp",
|
||||
extraitpoetique: "systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp",
|
||||
faune: "systems/foundryvtt-reve-de-dragon/icons/faune/rongeur.webp",
|
||||
gemme: "systems/foundryvtt-reve-de-dragon/icons/gemmes/almaze.webp",
|
||||
herbe: "systems/foundryvtt-reve-de-dragon/icons/botanique/Endorlotte.webp",
|
||||
ingredient: "systems/foundryvtt-reve-de-dragon/icons/objets/sable_poudre.webp",
|
||||
jeu: "systems/foundryvtt-reve-de-dragon/icons/arts/jeux_petasse.webp",
|
||||
recettecuisine: "systems/foundryvtt-reve-de-dragon/icons/arts/recette_cuisine_1.webp",
|
||||
musique: "systems/foundryvtt-reve-de-dragon/icons/arts/chant_0.webp",
|
||||
livre: "systems/foundryvtt-reve-de-dragon/icons/objets/livre.webp",
|
||||
maladie: "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/maladie.webp",
|
||||
poison: "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/venin.webp",
|
||||
oeuvre: "systems/foundryvtt-reve-de-dragon/icons/competence_comedie.webp",
|
||||
meditation: "systems/foundryvtt-reve-de-dragon/icons/meditations_ecrits/meditation_alchimie.webp",
|
||||
musique: "systems/foundryvtt-reve-de-dragon/icons/arts/chant_0.webp",
|
||||
nourritureboisson: "systems/foundryvtt-reve-de-dragon/icons/objets/provision_crue.webp",
|
||||
oeuvre: "systems/foundryvtt-reve-de-dragon/icons/competence_comedie.webp",
|
||||
ombre: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp",
|
||||
poison: "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/venin.webp",
|
||||
possession: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
|
||||
potion: "systems/foundryvtt-reve-de-dragon/icons/objets/liqueur_de_bagdol.webp",
|
||||
queue: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp",
|
||||
recettealchimique: "systems/foundryvtt-reve-de-dragon/icons/competence_alchimie.webp",
|
||||
recettecuisine: "systems/foundryvtt-reve-de-dragon/icons/arts/recette_cuisine_1.webp",
|
||||
rencontre: "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp",
|
||||
service: "systems/foundryvtt-reve-de-dragon/icons/services/lit.webp",
|
||||
signedraconique: "systems/foundryvtt-reve-de-dragon/icons/tmr/signe_draconique.webp",
|
||||
gemme: "systems/foundryvtt-reve-de-dragon/icons/gemmes/almaze.webp",
|
||||
possession: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
|
||||
sort: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp",
|
||||
sortreserve: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp",
|
||||
extraitpoetique: "systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp",
|
||||
souffle: "systems/foundryvtt-reve-de-dragon/icons/souffle_dragon.webp",
|
||||
tarot: "systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.webp",
|
||||
empoignade: "systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp"
|
||||
tete: "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp",
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDItem extends Item {
|
||||
|
||||
static get defaultIcon() {
|
||||
return undefined;
|
||||
}
|
||||
@ -130,12 +93,12 @@ export class RdDItem extends Item {
|
||||
static isFieldInventaireModifiable(type, field) {
|
||||
switch (field) {
|
||||
case 'quantite':
|
||||
if ([TYPES.conteneur].includes(type)) {
|
||||
if ([ITEM_TYPES.conteneur].includes(type)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'cout':
|
||||
if ([TYPES.monnaie].includes(type)) {
|
||||
if ([ITEM_TYPES.monnaie].includes(type)) {
|
||||
return game.user.isGM;
|
||||
}
|
||||
break;
|
||||
@ -153,9 +116,11 @@ export class RdDItem extends Item {
|
||||
static getItemTypesInventaire(mode = 'materiel') {
|
||||
return typesInventaire[mode ?? 'materiel']
|
||||
}
|
||||
|
||||
static getItemTypesDraconiques() {
|
||||
return typesObjetsDraconiques;
|
||||
}
|
||||
|
||||
static getItemTypesEnvironnement() {
|
||||
return typesEnvironnement;
|
||||
}
|
||||
@ -164,9 +129,19 @@ export class RdDItem extends Item {
|
||||
return typesObjetsOeuvres
|
||||
}
|
||||
|
||||
static getCategories(itemType) {
|
||||
switch (itemType) {
|
||||
case ITEM_TYPES.competence:
|
||||
return CATEGORIES_COMPETENCES
|
||||
case ITEM_TYPES.competencecreature:
|
||||
return CATEGORIES_COMPETENCES_CREATURES
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
constructor(docData, context = {}) {
|
||||
if (!context.rdd?.ready) {
|
||||
mergeObject(context, { rdd: { ready: true } });
|
||||
foundry.utils.mergeObject(context, { rdd: { ready: true } });
|
||||
const ItemConstructor = game.system.rdd.itemClasses[docData.type];
|
||||
if (ItemConstructor) {
|
||||
if (!docData.img) {
|
||||
@ -178,20 +153,21 @@ export class RdDItem extends Item {
|
||||
if (!docData.img) {
|
||||
docData.img = RdDItem.getDefaultImg(docData.type);
|
||||
}
|
||||
context.rdd = undefined
|
||||
super(docData, context);
|
||||
}
|
||||
|
||||
getUniteQuantite() {
|
||||
switch (this.type) {
|
||||
case TYPES.monnaie: return "(Pièces)"
|
||||
case TYPES.herbe:
|
||||
case ITEM_TYPES.monnaie: return "(Pièces)"
|
||||
case ITEM_TYPES.herbe:
|
||||
switch (this.system.categorie) {
|
||||
case 'Alchimie': case 'Repos': case 'Soin':
|
||||
return "(Brins)"
|
||||
case 'Cuisine': return '';
|
||||
}
|
||||
return '';
|
||||
case TYPES.ingredient: return "(Pépins ou Brins)"
|
||||
case ITEM_TYPES.ingredient: return "(Pépins ou Brins)"
|
||||
}
|
||||
return '';
|
||||
}
|
||||
@ -200,32 +176,54 @@ export class RdDItem extends Item {
|
||||
return typesObjetsEquipable.includes(this.type)
|
||||
}
|
||||
|
||||
isCompetencePersonnage() { return this.type == TYPES.competence }
|
||||
isCompetenceCreature() { return this.type == TYPES.competencecreature }
|
||||
isConteneur() { return this.type == TYPES.conteneur; }
|
||||
isMonnaie() { return this.type == TYPES.monnaie; }
|
||||
isPotion() { return this.type == TYPES.potion; }
|
||||
isNourritureBoisson() { return this.type == TYPES.nourritureboisson; }
|
||||
isService() { return this.type == TYPES.service; }
|
||||
isCompetencePersonnage() { return this.type == ITEM_TYPES.competence }
|
||||
isCompetenceCreature() { return this.type == ITEM_TYPES.competencecreature }
|
||||
isConteneur() { return this.type == ITEM_TYPES.conteneur; }
|
||||
isMonnaie() { return this.type == ITEM_TYPES.monnaie; }
|
||||
isNourritureBoisson() { return this.type == ITEM_TYPES.nourritureboisson; }
|
||||
isService() { return this.type == ITEM_TYPES.service; }
|
||||
|
||||
isCompetence() { return typesObjetsCompetence.includes(this.type) }
|
||||
isEsquive() {
|
||||
return (this.isCompetence()
|
||||
&& this.system.categorie == 'melee'
|
||||
&& Grammar.includesLowerCaseNoAccent(this.name, BASE_ESQUIVE.name));
|
||||
}
|
||||
|
||||
isCorpsACorps() {
|
||||
return this.isCompetence()
|
||||
&& this.system.categorie == 'melee'
|
||||
&& Grammar.includesLowerCaseNoAccent(this.name, BASE_CORPS_A_CORPS.name)
|
||||
}
|
||||
|
||||
isCompetenceArme() {
|
||||
return this.isCompetence() && ['melee', 'tir', 'lancer'].includes(this.system.categorie)
|
||||
}
|
||||
|
||||
isCompetencePossession() { return ITEM_TYPES.competencecreature == this.type && this.system.categorie == "possession" }
|
||||
isTemporel() { return typesObjetsTemporels.includes(this.type) }
|
||||
isOeuvre() { return typesObjetsOeuvres.includes(this.type) }
|
||||
isDraconique() { return RdDItem.getItemTypesDraconiques().includes(this.type) }
|
||||
isQueueDragon() { return [TYPES.queue, TYPES.ombre].includes(this.type) }
|
||||
isQueueDragon() { return [ITEM_TYPES.queue, ITEM_TYPES.ombre].includes(this.type) }
|
||||
isEffet() { return typesObjetsEffet.includes(this.type) }
|
||||
isConnaissance() { return typesObjetsConnaissance.includes(this.type) }
|
||||
|
||||
isInventaire(mode = 'materiel') { return RdDItem.getItemTypesInventaire(mode).includes(this.type); }
|
||||
isBoisson() { return this.isNourritureBoisson() && this.system.boisson; }
|
||||
isAlcool() { return this.isNourritureBoisson() && this.system.boisson && this.system.alcoolise; }
|
||||
isHerbeAPotion() { return this.type == TYPES.herbe && (this.system.categorie == 'Soin' || this.system.categorie == 'Repos'); }
|
||||
isBlessure() { return this.type == TYPES.blessure }
|
||||
isHerbeAPotion() { return this.type == ITEM_TYPES.herbe && (this.system.categorie == 'Soin' || this.system.categorie == 'Repos'); }
|
||||
isBlessure() { return this.type == ITEM_TYPES.blessure }
|
||||
|
||||
isPresentDansMilieux(milieux) {
|
||||
return this.getEnvironnements(milieux).length > 0
|
||||
}
|
||||
|
||||
get nameDisplay() {
|
||||
return this.isMagique ? (this.name + ' <i class="fa-solid fa-sparkles"></i>') : this.name
|
||||
}
|
||||
|
||||
get isEnchantementPossible() { return false }
|
||||
|
||||
getEnvironnements(milieux = undefined) {
|
||||
const environnements = this.isInventaire() ? this.system.environnement : undefined;
|
||||
if (milieux == undefined || !environnements) {
|
||||
@ -282,8 +280,8 @@ export class RdDItem extends Item {
|
||||
const timestampFin = await this.calculerFinPeriodeTemporel(timestampDebut);
|
||||
await actor.updateEmbeddedDocuments('Item', [{
|
||||
_id: this.id,
|
||||
'system.temporel.debut': duplicate(timestampDebut),
|
||||
'system.temporel.fin': duplicate(timestampFin),
|
||||
'system.temporel.debut': foundry.utils.duplicate(timestampDebut),
|
||||
'system.temporel.fin': foundry.utils.duplicate(timestampFin),
|
||||
}])
|
||||
}
|
||||
}
|
||||
@ -305,15 +303,8 @@ export class RdDItem extends Item {
|
||||
|
||||
getUtilisation() {
|
||||
switch (this.type) {
|
||||
case TYPES.potion:
|
||||
switch (this.system.categorie) {
|
||||
case 'Alchimie': case 'AlchimieEnchante': case 'AlchimieAutre': return 'alchimie'
|
||||
case 'Cuisine': return 'cuisine'
|
||||
case 'Remede': case 'Repos': case 'ReposEnchante': case 'Soin': case 'SoinEnchante': return 'soins'
|
||||
}
|
||||
return '';
|
||||
case TYPES.nourritureboisson: return 'cuisine';
|
||||
case TYPES.herbe: case TYPES.faune: case TYPES.ingredient: case TYPES.plante:
|
||||
case ITEM_TYPES.nourritureboisson: return 'cuisine';
|
||||
case ITEM_TYPES.herbe: case ITEM_TYPES.faune: case ITEM_TYPES.ingredient: case ITEM_TYPES.plante:
|
||||
switch (this.system.categorie) {
|
||||
case 'Cuisine': return 'cuisine';
|
||||
case 'Toxique': case 'Poison': return 'poison';
|
||||
@ -328,9 +319,9 @@ export class RdDItem extends Item {
|
||||
getUtilisationCuisine() {
|
||||
if (this.getUtilisation() == 'cuisine') {
|
||||
switch (this.type) {
|
||||
case TYPES.nourritureboisson:
|
||||
case ITEM_TYPES.nourritureboisson:
|
||||
return 'pret';
|
||||
case TYPES.herbe: case TYPES.faune: case TYPES.ingredient: case TYPES.plante:
|
||||
case ITEM_TYPES.herbe: case ITEM_TYPES.faune: case ITEM_TYPES.ingredient: case ITEM_TYPES.plante:
|
||||
return 'brut';
|
||||
}
|
||||
}
|
||||
@ -338,10 +329,10 @@ export class RdDItem extends Item {
|
||||
}
|
||||
|
||||
isCristalAlchimique() {
|
||||
return this.type == TYPES.objet && Grammar.includesLowerCaseNoAccent(this.name, 'cristal alchimique') && this.system.quantite > 0;
|
||||
return this.type == ITEM_TYPES.objet && Grammar.includesLowerCaseNoAccent(this.name, 'cristal alchimique') && this.system.quantite > 0;
|
||||
}
|
||||
|
||||
isMagique() {
|
||||
get isMagique() {
|
||||
return this.system.magique
|
||||
}
|
||||
|
||||
@ -352,6 +343,7 @@ export class RdDItem extends Item {
|
||||
isNomLike(texte) {
|
||||
return Grammar.includesLowerCaseNoAccent(this.name, texte)
|
||||
}
|
||||
|
||||
isNomTypeLike(texte) {
|
||||
return this.isNomLike(texte) || Grammar.includesLowerCaseNoAccent(Misc.typeName(this.type, 'Item'), texte)
|
||||
}
|
||||
@ -361,21 +353,29 @@ export class RdDItem extends Item {
|
||||
}
|
||||
|
||||
getEncTotal() {
|
||||
return (this.isService() ? 0 : this.getQuantite()) * this.getEnc();
|
||||
return (this.getQuantite() ?? 0) * this.getEnc();
|
||||
}
|
||||
|
||||
getEnc() {
|
||||
switch (this.type) {
|
||||
case TYPES.service:
|
||||
case ITEM_TYPES.service:
|
||||
return 0;
|
||||
case TYPES.herbe:
|
||||
case ITEM_TYPES.herbe:
|
||||
return this.getEncHerbe();
|
||||
case TYPES.gemme:
|
||||
return encPepin * this.system.taille;
|
||||
}
|
||||
return Math.max(this.system.encombrement ?? 0, 0);
|
||||
}
|
||||
|
||||
getEncContenu() {
|
||||
return this.getContenu()
|
||||
.map(it => it.getRecursiveEnc())
|
||||
.reduce(Misc.sum(), 0);
|
||||
}
|
||||
|
||||
getRecursiveEnc() {
|
||||
return this.getEncTotal() + this.getEncContenu()
|
||||
}
|
||||
|
||||
getEncHerbe() {
|
||||
switch (this.system.categorie) {
|
||||
case 'Repos': case 'Soin': case 'Alchimie':
|
||||
@ -385,6 +385,18 @@ export class RdDItem extends Item {
|
||||
|
||||
}
|
||||
|
||||
getContenu() {
|
||||
if (this.isConteneur()) {
|
||||
return this.system.contenu.map(idContenu => this.actor.getItem(idContenu));
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
isConteneurContenu(conteneur) {
|
||||
return this.getContenu()
|
||||
.find(it => it.id == conteneur.id || it.isConteneurContenu(conteneur))
|
||||
}
|
||||
|
||||
valeurTotale() {
|
||||
return (this.isService() ? 1 : this.getQuantite()) * this.valeur()
|
||||
}
|
||||
@ -398,79 +410,47 @@ export class RdDItem extends Item {
|
||||
// appliquer le pourcentage
|
||||
return this.parent.calculerPrix(this);
|
||||
}
|
||||
return this.system.cout;
|
||||
return this.system.cout
|
||||
}
|
||||
|
||||
prepareDerivedData() {
|
||||
super.prepareDerivedData();
|
||||
if (this.isInventaire()) {
|
||||
this.system.encTotal = this.getEncTotal();
|
||||
if (this.isPotion()) {
|
||||
this.prepareDataPotion()
|
||||
}
|
||||
this.system.actionPrincipale = this.getActionPrincipale({ warnIfNot: false });
|
||||
this.system.encTotal = this.getEncTotal()
|
||||
}
|
||||
this.equipable = this.isEquipable();
|
||||
this.equipable = this.isEquipable()
|
||||
}
|
||||
|
||||
prepareDataPotion() {
|
||||
const categorie = Grammar.toLowerCaseNoAccent(this.system.categorie);
|
||||
this.system.magique = categorie.includes('enchante');
|
||||
if (this.system.magique) {
|
||||
if (categorie.includes('soin') || categorie.includes('repos')) {
|
||||
// TODO: utiliser calculPointsRepos / calculPointsGuerison
|
||||
this.system.puissance = RdDHerbes.calculPuissancePotion(this);
|
||||
}
|
||||
}
|
||||
itemActions() {
|
||||
return COMMON_ACTIONS.concat(this.itemSpecificActions()).concat(DEFAULT_ACTIONS)
|
||||
}
|
||||
|
||||
getActionPrincipale(options = { warnIfNot: true }) {
|
||||
itemSpecificActions() {
|
||||
const actions = ITEM_ACTIONS[this.type] ?? []
|
||||
return actions
|
||||
}
|
||||
|
||||
isActionAllowed(code) {
|
||||
switch (this.type) {
|
||||
case TYPES.conteneur: return 'Ouvrir';
|
||||
}
|
||||
if (this.actor?.isPersonnage()) {
|
||||
const warn = options.warnIfNot;
|
||||
if (this.getUtilisationCuisine() == 'brut') {
|
||||
return 'Utiliser';
|
||||
}
|
||||
switch (this.type) {
|
||||
case TYPES.nourritureboisson: return this._actionOrWarnQuantiteZero(this.system.boisson ? 'Boire' : 'Manger', warn);
|
||||
case TYPES.potion: return this._actionOrWarnQuantiteZero('Boire', warn);
|
||||
case TYPES.livre: return this._actionOrWarnQuantiteZero('Lire', warn);
|
||||
case TYPES.herbe: return this.isHerbeAPotion() ? this._actionOrWarnQuantiteZero('Décoction', warn) : undefined;
|
||||
case TYPES.queue: case TYPES.ombre: return this.system.refoulement > 0 ? 'Refouler' : undefined;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async actionPrincipale(actor, onActionItem = async () => { }) {
|
||||
if (!this.getActionPrincipale()) {
|
||||
return;
|
||||
}
|
||||
if (await actor.actionNourritureboisson(this, onActionItem)) {
|
||||
return;
|
||||
}
|
||||
switch (this.type) {
|
||||
case TYPES.potion: return await actor.consommerPotion(this, onActionItem);
|
||||
case TYPES.livre: return await actor.actionLire(this);
|
||||
case TYPES.conteneur: return await this.sheet.render(true);
|
||||
case TYPES.herbe: return await actor.actionHerbe(this, onActionItem);
|
||||
case TYPES.queue: case TYPES.ombre: return await actor.actionRefoulement(this);
|
||||
}
|
||||
}
|
||||
|
||||
_actionOrWarnQuantiteZero(actionName, warn) {
|
||||
if ((this.system.quantite ?? 0) <= 0) {
|
||||
if (warn) {
|
||||
ui.notifications.warn(`Vous n'avez plus de ${this.name}.`);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
else {
|
||||
return actionName;
|
||||
case ITEM_TYPES.possession:
|
||||
case ITEM_TYPES.empoignade:
|
||||
case ITEM_TYPES.rencontre:
|
||||
case ITEM_TYPES.signedraconique:
|
||||
switch (code) {
|
||||
case 'item-edit':
|
||||
case 'item-delete':
|
||||
return game.user.isGM
|
||||
}
|
||||
case ITEM_TYPES.maladie:
|
||||
case ITEM_TYPES.poison:
|
||||
return game.user.isGM
|
||||
case ITEM_TYPES.casetmr:
|
||||
switch (code) {
|
||||
case 'item-delete':
|
||||
return game.user.isGM
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
async diminuerQuantite(nombre, options = { diminuerQuantite: true, supprimerSiZero: false }) {
|
||||
@ -492,7 +472,7 @@ export class RdDItem extends Item {
|
||||
_id: this.id,
|
||||
'system.quantite': this.system.quantite * sust,
|
||||
'system.encombrement': Misc.keepDecimals(this.system.encombrement / sust, 2),
|
||||
'system.cout': Misc.keepDecimals(this.system.cout / sust, 2),
|
||||
'system.cout': Math.max(0, Misc.keepDecimals(this.system.cout / sust, 2)),
|
||||
'system.sust': 1
|
||||
}])
|
||||
}
|
||||
@ -511,6 +491,7 @@ export class RdDItem extends Item {
|
||||
else {
|
||||
await this.quantiteIncDec(item.system.quantite);
|
||||
}
|
||||
// TODO: suppression dans les conteneurs!
|
||||
await item.delete();
|
||||
}
|
||||
|
||||
@ -541,6 +522,9 @@ export class RdDItem extends Item {
|
||||
if (!other || !this.isInventaire()) {
|
||||
return [false, undefined];
|
||||
}
|
||||
if (this.isConteneur()) {
|
||||
return [false, `Impossible de regrouper des conteneurs, ils ne sont pas empilables`];
|
||||
}
|
||||
if (this.system.quantite == undefined) {
|
||||
return [false, `Impossible de regrouper des ${this.type}, ils ne sont pas empilables`];
|
||||
}
|
||||
@ -575,23 +559,7 @@ export class RdDItem extends Item {
|
||||
ui.notifications.warn(`Votre ${this.name} n'est pas vide, pas possible de le proposer`);
|
||||
return;
|
||||
}
|
||||
await DialogItemVente.display({
|
||||
item: this,
|
||||
quantiteMax,
|
||||
callback: async (vente) => {
|
||||
vente["properties"] = this.getProprietes();
|
||||
if (vente.isOwned) {
|
||||
if (vente.quantiteNbLots * vente.tailleLot > vente.quantiteMax) {
|
||||
ui.notifications.warn(`Vous avez ${vente.quantiteMax} ${vente.item.name}, ce n'est pas suffisant pour vendre ${vente.quantiteNbLots} de ${vente.tailleLot}`)
|
||||
return;
|
||||
}
|
||||
}
|
||||
vente.jsondata = JSON.stringify(vente.item);
|
||||
|
||||
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente);
|
||||
ChatMessage.create(RdDUtility.chatDataSetup(html));
|
||||
}
|
||||
});
|
||||
await DialogItemVente.display({ item: this, quantiteMax })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -656,7 +624,7 @@ export class RdDItem extends Item {
|
||||
_armeChatData() {
|
||||
return [
|
||||
`<b>Compétence</b>: ${this.system.competence}`,
|
||||
`<b>Dommages</b>: ${this.system.dommages}`,
|
||||
`<b>Dommages</b>: ${this.system.dommages} ${this.system.mortalite == 'non-mortel' ? '(Non mortel)' : ''}`,
|
||||
`<b>Force minimum</b>: ${this.system.force}`,
|
||||
`<b>Resistance</b>: ${this.system.resistance}`,
|
||||
...this._inventaireTemplateChatData()
|
||||
@ -741,7 +709,7 @@ export class RdDItem extends Item {
|
||||
`<b>Périodicité</b>: ${this.system.periodicite}`,
|
||||
`<b>Fatigue</b>: ${this.system.fatigue}`,
|
||||
`<b>Difficulté</b>: ${this.system.difficulte}`,
|
||||
RdDItem.propertyIfDefined('Points de Tâche', this.system.points_de_tache, this.system.cacher_points_de_tache),
|
||||
RdDItem.propertyIfDefined('Points de Tâche', this.system.points_de_tache, !this.system.cacher_points_de_tache),
|
||||
`<b>Points de Tâche atteints</b>: ${this.system.points_de_tache_courant}`]
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
@ -750,15 +718,7 @@ export class RdDItem extends Item {
|
||||
`<b>Compétence</b>: ${this.system.competence}`,
|
||||
`<b>Auteur</b>: ${this.system.auteur}`,
|
||||
`<b>Difficulté</b>: ${this.system.difficulte}`,
|
||||
RdDItem.propertyIfDefined('Points de Tâche', this.system.points_de_tache, this.system.cacher_points_de_tache),
|
||||
...this._inventaireTemplateChatData()
|
||||
]
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
_potionChatData() {
|
||||
return [
|
||||
`<b>Rareté</b>: ${this.system.rarete}`,
|
||||
`<b>Catégorie</b>: ${this.system.categorie}`,
|
||||
RdDItem.propertyIfDefined('Points de Tâche', this.system.points_de_tache, !this.system.cacher_points_de_tache),
|
||||
...this._inventaireTemplateChatData()
|
||||
]
|
||||
}
|
||||
|
@ -1,15 +1,18 @@
|
||||
import { ITEM_TYPES } from "../constants.js";
|
||||
import { RdDItem } from "../item.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { ReglesOptionelles } from "../settings/regles-optionelles.js";
|
||||
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
|
||||
|
||||
export class RdDItemArmure extends RdDItem {
|
||||
|
||||
static get ITEM_TYPE() { return ITEM_TYPES.armure }
|
||||
|
||||
static get defaultIcon() {
|
||||
return "systems/foundryvtt-reve-de-dragon/icons/armes_armures/armure_plaques.webp";
|
||||
}
|
||||
|
||||
deteriorerArmure(dmg) {
|
||||
if (!ReglesOptionelles.isUsing('deteriorationArmure') || this.system.protection == '0') {
|
||||
async deteriorerArmure(dmg) {
|
||||
if (!ReglesOptionnelles.isUsing('deteriorationArmure') || this.system.protection == '0') {
|
||||
return;
|
||||
}
|
||||
let deterioration = (this.system.deterioration ?? 0) + dmg;
|
||||
@ -20,12 +23,10 @@ export class RdDItemArmure extends RdDItem {
|
||||
protection = this.calculProtectionDeterioree();
|
||||
ChatMessage.create({ content: `Votre armure ${this.name} s'est détériorée, elle protège maintenant de ${protection}` });
|
||||
}
|
||||
this.update({
|
||||
system: {
|
||||
deterioration: deterioration,
|
||||
protection: protection
|
||||
}
|
||||
});
|
||||
await this.update({
|
||||
'system.deterioration': deterioration,
|
||||
'system.protection': protection
|
||||
})
|
||||
}
|
||||
|
||||
calculProtectionDeterioree() {
|
||||
|
20
module/item/base-items.js
Normal file
@ -0,0 +1,20 @@
|
||||
export const POSSESSION_SANS_DRACONIC = { name: 'Sans draconic', type: 'competence', system: { niveau: 0, defaut_carac: "reve-actuel", }, img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp' }
|
||||
export const PAS_DE_DRACONIC = { name: 'Pas de draconic', type: 'competence', system: { niveau: -11, defaut_carac: "reve" }, img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp' }
|
||||
export const BASE_CORPS_A_CORPS = { name: 'Corps à Corps', type: 'competence', system: { niveau: -6, defaut_carac: "melee" }, img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp' }
|
||||
export const BASE_ESQUIVE = { name: 'Esquive', type: 'competence', system: { niveau: -6, defaut_carac: "derobee" }, img: 'systems/foundryvtt-reve-de-dragon/icons/competence_esquive.webp' }
|
||||
|
||||
export const SANS_COMPETENCE = {
|
||||
name: "Sans compétence",
|
||||
type: 'competence',
|
||||
system: {
|
||||
niveau: 0,
|
||||
default_diffLibre: 0,
|
||||
base: 0,
|
||||
categorie: "Aucune",
|
||||
description: "",
|
||||
descriptionmj: "",
|
||||
defaut_carac: "",
|
||||
},
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp"
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { RdDItem } from "../item.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { RdDTimestamp } from "../time/rdd-timestamp.js";
|
||||
import { ChatUtility } from "../chat-utility.js";
|
||||
|
||||
const BASE_TACHE_SOIN_BLESSURE = {
|
||||
type: "tache",
|
||||
@ -14,10 +15,10 @@ const TACHES_SOIN_BLESSURE = {
|
||||
}
|
||||
|
||||
const definitionsBlessures = [
|
||||
{ type: "contusion", gravite: 0, label: 'Contusion/éraflure', max: 100, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/eraflure.webp" },
|
||||
{ type: "legere", gravite: 2, label: 'Légère', max: 5, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
|
||||
{ type: "grave", gravite: 4, label: 'Grave', max: 2, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
|
||||
{ type: "critique", gravite: 6, label: 'Critique', max: 1, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
|
||||
{ type: "contusion", gravite: 0, endurance: "1d4", vie: 0, label: 'Contusion/éraflure', max: 100, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/eraflure.webp" },
|
||||
{ type: "legere", gravite: 2, endurance: "1d6", vie: 0, label: 'Légère', max: 5, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
|
||||
{ type: "grave", gravite: 4, endurance: "2d6", vie: -2, label: 'Grave', max: 2, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
|
||||
{ type: "critique", gravite: 6, endurance: "-100", vie: -4, label: 'Critique', max: 1, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
|
||||
{ type: "mort", gravite: 8, label: 'Mort', max: 1, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/mort.webp" }
|
||||
]
|
||||
|
||||
@ -29,7 +30,7 @@ export class RdDItemBlessure extends RdDItem {
|
||||
|
||||
prepareDerivedData() {
|
||||
super.prepareDerivedData();
|
||||
this.system.label = this.getLabelGravite()
|
||||
this.system.label = RdDItemBlessure.getLabelGravite(this.system.gravite)
|
||||
}
|
||||
|
||||
static prepareTacheSoin(gravite) {
|
||||
@ -38,9 +39,39 @@ export class RdDItemBlessure extends RdDItem {
|
||||
ui.notifications.warn(`Pas de tâche de soins pour une blessure ${gravite}`)
|
||||
return undefined;
|
||||
}
|
||||
return mergeObject(duplicate(BASE_TACHE_SOIN_BLESSURE), tache)
|
||||
return foundry.utils.mergeObject(BASE_TACHE_SOIN_BLESSURE, tache, { inplace: false })
|
||||
}
|
||||
static async createBlessure(actor, gravite, localisation = '', attacker) {
|
||||
|
||||
static async applyFullBlessure(actor, gravite) {
|
||||
const definition = foundry.utils.duplicate(RdDItemBlessure.getDefinition(gravite))
|
||||
|
||||
if (definition.vie) {
|
||||
await actor.santeIncDec("vie", definition.vie)
|
||||
}
|
||||
const lostEndurance = await RdDItemBlessure.rollLostEndurance(definition.endurance)
|
||||
if (lostEndurance) {
|
||||
await actor.santeIncDec("endurance", -Number(lostEndurance));
|
||||
}
|
||||
await this.createBlessure(actor, gravite)
|
||||
|
||||
ChatMessage.create({
|
||||
//TODO: hbs
|
||||
content: `Blessure ${definition.label} appliquée à ${actor.name}<br>Perte d'endurance : ${lostEndurance} (${definition.endurance})<br>Perte de Vie : ${definition.vie}`,
|
||||
whisper: ChatUtility.getOwners(actor)
|
||||
});
|
||||
actor.sheet?.render()
|
||||
}
|
||||
|
||||
static async rollLostEndurance(formula) {
|
||||
if (formula) {
|
||||
const roll = new Roll(formula)
|
||||
await roll.evaluate()
|
||||
return roll.total
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
static async createBlessure(actor, gravite, localisation = '', attackerToken) {
|
||||
const definition = RdDItemBlessure.getDefinition(gravite)
|
||||
const blessure = {
|
||||
name: definition.label,
|
||||
@ -50,7 +81,7 @@ export class RdDItemBlessure extends RdDItem {
|
||||
gravite: gravite,
|
||||
difficulte: - gravite,
|
||||
localisation: localisation,
|
||||
origine: attacker?.name ?? ""
|
||||
origine: attackerToken?.name ?? ""
|
||||
}
|
||||
}
|
||||
const blessures = await actor.createEmbeddedDocuments('Item', [blessure])
|
||||
@ -79,12 +110,12 @@ export class RdDItemBlessure extends RdDItem {
|
||||
}
|
||||
|
||||
async setSoinsBlessure(systemUpdate = {}) {
|
||||
systemUpdate = mergeObject(systemUpdate, this.system, { overwrite: false }),
|
||||
systemUpdate.soinscomplets.done = systemUpdate.premierssoins.done && systemUpdate.soinscomplets.done
|
||||
systemUpdate = foundry.utils.mergeObject(systemUpdate, this.system, { overwrite: false })
|
||||
systemUpdate.soinscomplets.done = systemUpdate.premierssoins.done && systemUpdate.soinscomplets.done
|
||||
await this.update({
|
||||
img: this.getImgSoins(systemUpdate.gravite, systemUpdate.soinscomplets.done),
|
||||
system: systemUpdate
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
async recuperationBlessure({ actor, timestamp, message, isMaladeEmpoisonne, blessures }) {
|
||||
@ -97,25 +128,28 @@ export class RdDItemBlessure extends RdDItem {
|
||||
}
|
||||
if (this.system.gravite > 0) {
|
||||
const update = { system: { premierssoins: { bonus: 0 }, soinscomplets: { bonus: 0 } } }
|
||||
const gravite = this.system.gravite;
|
||||
const graviteMoindre = gravite - 2;
|
||||
const gravite = this.system.gravite
|
||||
const graviteMoindre = gravite - 2
|
||||
const moindres = blessures.filter(it => it.system.gravite == graviteMoindre, 'blessures').length
|
||||
const label = this.getLabelGravite();
|
||||
const label = RdDItemBlessure.getLabelGravite(this.system.gravite)
|
||||
|
||||
let rolled = await actor.jetRecuperationConstitution(this.system.soinscomplets.bonus, message);
|
||||
|
||||
if (rolled.isETotal) {
|
||||
message.content += ` -- une blessure ${label} s'infecte (temps de guérison augmenté de ${gravite} jours, perte de vie)`;
|
||||
await actor.santeIncDec("vie", -1);
|
||||
mergeObject(update, {
|
||||
foundry.utils.mergeObject(update, {
|
||||
system: { fin: { indexDate: timestamp.addJours(gravite).indexDate } }
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (!isMaladeEmpoisonne && rolled.isSuccess && this.peutRetrograder(graviteMoindre, moindres)) {
|
||||
message.content += ` -- une blessure ${label} cicatrise`;
|
||||
mergeObject(update, {
|
||||
system: { gravite: graviteMoindre, fin: { indexDate: timestamp.addJours(graviteMoindre).indexDate } }
|
||||
foundry.utils.mergeObject(update, {
|
||||
system: {
|
||||
gravite: graviteMoindre,
|
||||
temporel: { fin: { indexDate: timestamp.addJours(graviteMoindre).indexDate } }
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
@ -127,11 +161,11 @@ export class RdDItemBlessure extends RdDItem {
|
||||
}
|
||||
|
||||
peutRetrograder(graviteMoindre, moindres) {
|
||||
return moindres < RdDItemBlessure.getDefinition(graviteMoindre).max
|
||||
return moindres < RdDItemBlessure.maxBlessures(graviteMoindre)
|
||||
}
|
||||
|
||||
async calculerFinPeriodeTemporel(debut) {
|
||||
return await debut.nouveauJour().addJours(this.system.gravite);
|
||||
return debut.nouveauJour().addJours(this.system.gravite);
|
||||
}
|
||||
|
||||
async onFinPeriode(oldTimestamp, newTimestamp) {
|
||||
@ -151,16 +185,16 @@ export class RdDItemBlessure extends RdDItem {
|
||||
return `systems/foundryvtt-reve-de-dragon/icons/sante/${soins ? 'blessure-soins' : img}.webp`
|
||||
}
|
||||
|
||||
getLabelGravite() {
|
||||
return RdDItemBlessure.getDefinition(this.system.gravite).label
|
||||
static getLabelGravite(gravite) {
|
||||
return definitionsBlessures.find(it => it.gravite >= gravite).label
|
||||
}
|
||||
|
||||
static getDefinition(gravite) {
|
||||
return definitionsBlessures.sort(Misc.ascending(it => it.gravite))
|
||||
.find(it => it.gravite >= gravite);
|
||||
return definitionsBlessures.find(it => it.gravite >= gravite)
|
||||
}
|
||||
|
||||
static maxBlessures(gravite) {
|
||||
return RdDItemBlessure.getDefinition(gravite).max
|
||||
return definitionsBlessures.find(it => it.gravite >= gravite).max
|
||||
}
|
||||
|
||||
isContusion() {
|
||||
@ -185,7 +219,7 @@ export class RdDItemBlessure extends RdDItem {
|
||||
`<b>Heure et Date</b>: ${new RdDTimestamp(this.system.temporel.debut).formatDateHeure()}`,
|
||||
RdDItem.propertyIfDefined('Blessé', this.parent?.name, this.parent),
|
||||
`<b>Localisation</b>: ${this.system.localisation}`,
|
||||
`<b>Gravité</b>: ${RdDItemBlessure.getDefinition(this.system.gravite).label}`,
|
||||
`<b>Gravité</b>: ${this.system.label}`,
|
||||
`<b>Difficulté des soins</b>: ${this.system.difficulte}`,
|
||||
(this.system.soinscomplets.done ?
|
||||
`<b>Bonus soins complets</b>: ${this.system.soinscomplets.bonus}` :
|
||||
|
112
module/item/gemme.js
Normal file
@ -0,0 +1,112 @@
|
||||
import { RdDItem } from "../item.js";
|
||||
import { ACTION_ITEM_ENCHANTER } from "../enchantement/dialog-enchanter.js";
|
||||
|
||||
const tableGemmes = {
|
||||
"almaze": { label: "Almaze", couleur: "Blanc" },
|
||||
"aquafane": { label: "Aquafane", couleur: "Vert Profond" },
|
||||
"asterite": { label: "Astérite", couleur: "Bleu, Violet ou Blanc" },
|
||||
"cyanolithe": { label: "Cyanolithe", couleur: "Bleu Intense" },
|
||||
"larmededragon": { label: "Larme de Dragon", couleur: "Rouge Intense" },
|
||||
"muska": { label: "Muska", couleur: "Violet Profond" },
|
||||
"nebuleuse": { label: "Nébuleuse", couleur: "Brouillard Intense" },
|
||||
"nebuleuse": { label: "Nébuleuse", couleur: "Brouillard Intense, Rose, Vert ou Bleu Pâle" },
|
||||
"oeildetigre": { label: "Oeil de Tigre", couleur: "Jaune" },
|
||||
"scarlatine": { label: "Scarlatine", couleur: "Rouge Clair ou Orangé" },
|
||||
"seliphane": { label: "Séliphane", couleur: "Vert Lumineux" },
|
||||
"tournelune": { label: "Tournelune", couleur: "Violet ou Bleu" },
|
||||
"zebraide": { label: "Zebraïde", couleur: "Bandes Bicolores, toutes couleurs" }
|
||||
}
|
||||
|
||||
/**
|
||||
* un pépin de gemme = 1/10 cm3 = 1/1000 l = 3.5/1000 kg = 7/2000 kg = 7/1000 enc
|
||||
* densité 3.5 (~2.3 à 4, parfois plus) -- https://www.juwelo.fr/guide-des-pierres/faits-et-chiffres/
|
||||
*/
|
||||
const encPepin = 0.0007;
|
||||
|
||||
/**
|
||||
* Item pour gérer les gemmes
|
||||
*/
|
||||
export class RdDItemGemme extends RdDItem {
|
||||
|
||||
static getGemmeTypeOptionList() {
|
||||
// TODO: look how to map object key-value pairs
|
||||
let options = ""
|
||||
for (let gemmeKey in tableGemmes) {
|
||||
options += `<option value="${gemmeKey}">${tableGemmes[gemmeKey].label}</option>`
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
static get defaultIcon() {
|
||||
return "systems/foundryvtt-reve-de-dragon/icons/gemmes/almaze.webp"
|
||||
}
|
||||
|
||||
get isEnchantementPossible() {
|
||||
return this.enchantabilite > 0
|
||||
}
|
||||
|
||||
get inertie() { return 7 - Number(this.system.purete) }
|
||||
get enchantabilite() { return this.system.taille - this.inertie }
|
||||
|
||||
getEnc() {
|
||||
return encPepin * this.system.taille;
|
||||
}
|
||||
|
||||
itemSpecificActions() {
|
||||
return [ACTION_ITEM_ENCHANTER]
|
||||
}
|
||||
|
||||
prepareDerivedData() {
|
||||
super.prepareDerivedData()
|
||||
this.system.cout = (this.system.taille * this.system.purete) + this.system.qualite
|
||||
this.system.inertie = this.inertie
|
||||
this.system.enchantabilite = this.enchantabilite
|
||||
}
|
||||
|
||||
getUtilisation() {
|
||||
switch (this.system.categorie) {
|
||||
case 'Alchimie': case 'Autre': case 'AlchimieAutre':
|
||||
// TODO: distinguer les remèdes alchimiques enchantables/non
|
||||
return 'alchimie'
|
||||
case 'Cuisine':
|
||||
return 'cuisine'
|
||||
case 'Remede': case 'Repos': case 'Soin':
|
||||
return 'soins'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
getProprietes() {
|
||||
const proprietes = [
|
||||
`<b>Taille</b>: ${this.system.taille}`,
|
||||
`<b>Pureté</b>: ${this.system.purete}`,
|
||||
`<b>Inertie</b>: ${this.system.inertie}`,
|
||||
`<b>Enchantabilité</b>: ${this.system.enchantabilite}`
|
||||
]
|
||||
const proprietesMagiques = this.system.magique ? [
|
||||
`<b>Enchantée</b> <i class="fa-solid fa-sparkles"></i> ${this.system.purifie ? ', purifiée' : ''} ${this.system.prpermanent ? 'permanente' : ''} `,
|
||||
`<b>Points de rêve</b>: ${this.system.pr}`,
|
||||
`<b>Puissance</b>: ${this.system.puissance}`,
|
||||
] : []
|
||||
return proprietes
|
||||
.concat(proprietesMagiques)
|
||||
.concat(this._inventaireTemplateChatData())
|
||||
.filter(it => it != undefined)
|
||||
}
|
||||
|
||||
perteReveChateauDormant() {
|
||||
if (this.system.magique && !this.system.prpermanent && this.system.pr > 0) {
|
||||
const nouveauReve = Math.max(this.system.pr - 1, 0)
|
||||
return {
|
||||
alias: this.parent.getAlias(),
|
||||
item: this,
|
||||
update: {
|
||||
_id: this.id,
|
||||
'system.pr': nouveauReve,
|
||||
'system.magique': nouveauReve > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
}
|
146
module/item/item-actions.js
Normal file
@ -0,0 +1,146 @@
|
||||
import { Misc } from "../misc.js"
|
||||
import { RdDSheetUtility } from "../rdd-sheet-utility.js"
|
||||
import { RdDUtility } from "../rdd-utility.js"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* options.editable ?
|
||||
*
|
||||
*/
|
||||
const _SPACEHOLDER = { placeholder: true }
|
||||
|
||||
const _VENDRE = {
|
||||
code: 'item-vendre', label: 'Vendre ou donner', icon: it => 'fa-solid fa-comments-dollar',
|
||||
filter: it => Misc.toInt(it.system.quantite) > 0,
|
||||
optionsFilter: options => options.editable,
|
||||
action: (item, actor) => item.proposerVente()
|
||||
}
|
||||
const _ACHAT_SERVICE = {
|
||||
code: 'item-service-acheter', label: 'Acheter', icon: it => 'fa-regular fa-coins',
|
||||
//filter: it => Misc.toInt(it.system.quantite) > 0,
|
||||
//optionsFilter: options => options.editable,
|
||||
//action: (item, actor) => item.proposerVente()
|
||||
}
|
||||
const _MONTRER = {
|
||||
code: 'item-montrer', label: 'Montrer', icon: it => 'fa-solid fa-comment',
|
||||
action: (item, actor) => item.postItemToChat()
|
||||
}
|
||||
const _SPLIT = {
|
||||
code: 'item-split', label: 'Séparer le goupe', icon: it => 'fa-solid fa-unlink',
|
||||
filter: it => Misc.toInt(it.system.quantite) > 1,
|
||||
action: (item, actor) => RdDSheetUtility.splitItem(item, actor)
|
||||
}
|
||||
|
||||
const _EDIT = {
|
||||
code: 'item-edit', label: 'Editer', icon: it => 'fa-solid fa-edit',
|
||||
action: (item, actor) => item.sheet.render(true)
|
||||
}
|
||||
const _DELETE = {
|
||||
code: 'item-delete', label: 'Supprimer', icon: it => 'fa-solid fa-trash',
|
||||
optionsFilter: options => options.editable && options.isOwner,
|
||||
action: (item, actor) => RdDUtility.confirmActorItemDelete(item, actor)
|
||||
}
|
||||
const _EQUIPER = {
|
||||
code: 'item-equip', label: 'Equiper', icon: it => it.system.equipe ? 'fa-solid fa-hand-rock' : 'fa-regular fa-hand-paper',
|
||||
filter: it => !it.estContenu && it.isEquipable(),
|
||||
action: (item, actor) => actor.equiperObjet(item)
|
||||
}
|
||||
|
||||
const _CUISINER = {
|
||||
code: 'item-cuisiner', label: 'Cuisiner', icon: it => 'fa-solid fa-utensils',
|
||||
filter: it => it.getUtilisation() == 'cuisine' && it.system.sust > 0,
|
||||
optionsFilter: options => options.editable,
|
||||
action: (item, actor) => actor.preparerNourriture(item)
|
||||
}
|
||||
const _MANGER_CRU = {
|
||||
code: 'item-manger-cru', label: 'Manger cru', icon: it => 'fa-solid fa-drumstick-bite',
|
||||
filter: it => it.getUtilisation() == 'cuisine' && it.system.sust > 0,
|
||||
optionsFilter: options => options.editable,
|
||||
action: (item, actor) => actor.mangerNourriture(item)
|
||||
}
|
||||
const _MANGER = {
|
||||
code: 'item-manger', label: 'Manger', icon: it => 'fa-solid fa-utensils',
|
||||
filter: it => !(it.system.boisson),
|
||||
optionsFilter: options => options.editable,
|
||||
action: (item, actor) => actor.mangerNourriture(item)
|
||||
}
|
||||
const _BOIRE = {
|
||||
code: 'item-boire', label: 'Boire', icon: it => 'fa-solid fa-glass-water',
|
||||
filter: it => it.system.boisson,
|
||||
optionsFilter: options => options.editable,
|
||||
action: (item, actor) => actor.mangerNourriture(item)
|
||||
}
|
||||
const _DECOCTION = {
|
||||
code: 'item-decoction', label: 'Décoction', icon: it => 'fa-solid fa-flask-vial',
|
||||
optionsFilter: options => options.editable,
|
||||
action: (item, actor) => actor.fabriquerDecoctionHerbe(item)
|
||||
}
|
||||
const _OUVRIR = {
|
||||
code: 'item-edit', label: 'Ouvrir', icon: it => 'fa-solid fa-eye',
|
||||
action: (item, actor) => item.sheet.render(true)
|
||||
}
|
||||
|
||||
const _LIRE = {
|
||||
code: 'item-lire', label: 'Lire', icon: it => 'fa-solid fa-book-open',
|
||||
optionsFilter: options => options.editable,
|
||||
action: (item, actor) => actor.actionLire(item)
|
||||
}
|
||||
|
||||
const _REFOULER = {
|
||||
code: 'item-refouler', label: 'Refouler', icon: it => 'fa-solid fa-burst',
|
||||
filter: it => it.system.refoulement > 0,
|
||||
optionsFilter: options => options.editable,
|
||||
action: (item, actor) => actor.actionRefoulement(item)
|
||||
}
|
||||
|
||||
const _SORT_RESERVE = {
|
||||
code: 'item-sortreserve-add', label: 'Ajouter en réserve', icon: it => 'fa-solid fa-sparkles',
|
||||
filter: it => game.user.isGM && !it.system.isrituel,
|
||||
action: (item, actor) => actor.addSortReserve(item)
|
||||
}
|
||||
|
||||
export const COMMON_ACTIONS = [_EQUIPER]
|
||||
export const DEFAULT_ACTIONS = [_SPACEHOLDER, _SPLIT, _VENDRE, _MONTRER, _EDIT, _DELETE]
|
||||
|
||||
export const ITEM_ACTIONS = {
|
||||
faune: [_CUISINER, _MANGER_CRU],
|
||||
ingredient: [_CUISINER, _MANGER_CRU],
|
||||
conteneur: [_OUVRIR],
|
||||
herbe: [_DECOCTION, _CUISINER, _MANGER_CRU],
|
||||
livre: [_LIRE],
|
||||
nourritureboisson: [_MANGER, _BOIRE],
|
||||
ombre: [_REFOULER],
|
||||
plante: [_CUISINER, _MANGER_CRU],
|
||||
queue: [_REFOULER],
|
||||
sort: [_SORT_RESERVE],
|
||||
service: [_ACHAT_SERVICE]
|
||||
}
|
||||
|
||||
|
||||
export class ItemAction {
|
||||
|
||||
static applies(action, item, options) {
|
||||
return action && item
|
||||
&& item.isActionAllowed(action.code)
|
||||
&& (!action.filter || action.filter(item))
|
||||
&& (!action.optionsFilter || action.optionsFilter(options))
|
||||
}
|
||||
|
||||
static icon(action, item) {
|
||||
if (action && action.icon) {
|
||||
return action.icon(item)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
static onActionItem(event, actor, options) {
|
||||
const item = RdDSheetUtility.getItem(event, actor)
|
||||
const code = $(event.currentTarget).data('code')
|
||||
const action = item?.itemActions().find(it => it.code == code)
|
||||
if (action && (!action.optionsFilter || action.optionsFilter(options))) {
|
||||
action.action(item, actor)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
import { ChatUtility } from "../chat-utility.js";
|
||||
import { RdDItem } from "../item.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { RdDTimestamp } from "../time/rdd-timestamp.js";
|
||||
@ -9,7 +10,7 @@ export class RdDItemMaladie extends RdDItem {
|
||||
}
|
||||
|
||||
async calculerFinPeriodeTemporel(debut) {
|
||||
return await debut.addPeriode(this.system.periode.nombre, this.system.periode.unite);
|
||||
return debut.addPeriode(this.system.periode.nombre, this.system.periode.unite);
|
||||
}
|
||||
|
||||
async onFinPeriode(oldTimestamp, newTimestamp) {
|
||||
@ -21,9 +22,12 @@ export class RdDItemMaladie extends RdDItem {
|
||||
const souffrance = mal.system.identifie
|
||||
? `de ${mal.name}`
|
||||
: `d'un mal inconnu`
|
||||
ChatMessage.create({ content: `${mal.actor.name} souffre ${souffrance} (${Misc.typeName('Item', mal.type)}): vérifiez que les effets ne se sont pas aggravés !` });
|
||||
mal.postItemToChat('gmroll');
|
||||
await RdDItemMaladie.prolongerPeriode(mal,oldTimestamp, newTimestamp);
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getOwners(mal.actor),
|
||||
content: `${mal.actor.name} souffre ${souffrance} (${Misc.typeName('Item', mal.type)}): vérifiez que les effets ne se sont pas aggravés !`
|
||||
})
|
||||
mal.postItemToChat('gmroll')
|
||||
await RdDItemMaladie.prolongerPeriode(mal, oldTimestamp, newTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +42,7 @@ export class RdDItemMaladie extends RdDItem {
|
||||
|
||||
await mal.actor.updateEmbeddedDocuments('Item', [{
|
||||
_id: mal.id,
|
||||
'system.temporel.fin': duplicate(timestampFin),
|
||||
'system.temporel.fin': foundry.utils.duplicate(timestampFin),
|
||||
}])
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,8 @@
|
||||
import { RdDItem } from "../item.js";
|
||||
import { RdDItemQueue } from "./queue.js";
|
||||
|
||||
export class RdDItemOmbre extends RdDItemQueue {
|
||||
|
||||
export class RdDItemOmbre extends RdDItem {
|
||||
static get defaultIcon() {
|
||||
return "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp";
|
||||
}
|
||||
|
||||
async calculerFinPeriodeTemporel(debut) {
|
||||
return await debut.appliquerDuree(this.system.duree, this.parent);
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ export class RdDItemPoison extends RdDItem {
|
||||
}
|
||||
|
||||
async calculerFinPeriodeTemporel(debut) {
|
||||
return await debut.addPeriode(this.system.periode.nombre, this.system.periode.unite) ;
|
||||
return debut.addPeriode(this.system.periode.nombre, this.system.periode.unite) ;
|
||||
}
|
||||
|
||||
async onFinPeriode(oldTimestamp, newTimestamp) {
|
||||
|
105
module/item/potion.js
Normal file
@ -0,0 +1,105 @@
|
||||
import { Grammar } from "../grammar.js";
|
||||
import { RdDItem } from "../item.js";
|
||||
import { SystemCompendiums } from "../settings/system-compendiums.js";
|
||||
import { ACTION_ITEM_ENCHANTER } from "../enchantement/dialog-enchanter.js";
|
||||
|
||||
// --- Actions sur les "potions"
|
||||
const _CONSOMMER_POTION = {
|
||||
code: 'item-potion-consommer', label: 'Consommer', icon: it => 'fa-solid fa-vial',
|
||||
optionsFilter: options => options.editable,
|
||||
action: (item, actor) => actor.consommerPotion(item)
|
||||
}
|
||||
|
||||
/**
|
||||
* Item pour gérer les potions
|
||||
*/
|
||||
export class RdDItemPotion extends RdDItem {
|
||||
|
||||
static async herbesSoins() {
|
||||
return await RdDItemPotion.$listHerbes(it => Grammar.equalsInsensitive(it.system.categorie, 'Soin') && it.system.niveau > 0)
|
||||
}
|
||||
static async herbesRepos() {
|
||||
return await RdDItemPotion.$listHerbes(it => Grammar.equalsInsensitive(it.system.categorie, 'Repos') && it.system.niveau > 0)
|
||||
}
|
||||
|
||||
static async $listHerbes(filter) {
|
||||
const herbes = await SystemCompendiums.getWorldOrCompendiumItems('herbe', 'faune-flore-mineraux');
|
||||
return herbes.filter(filter)
|
||||
}
|
||||
|
||||
static get defaultIcon() {
|
||||
return "systems/foundryvtt-reve-de-dragon/icons/objets/liqueur_de_bagdol.webp"
|
||||
}
|
||||
|
||||
get isEnchantementPossible() {
|
||||
return this.system.etat == 'Liquide'
|
||||
}
|
||||
|
||||
itemSpecificActions() {
|
||||
return [_CONSOMMER_POTION, ACTION_ITEM_ENCHANTER]
|
||||
}
|
||||
|
||||
prepareDerivedData() {
|
||||
super.prepareDerivedData()
|
||||
this.system.puissance = this.system.magique ? this.calculPuissance() : 0
|
||||
}
|
||||
|
||||
getUtilisation() {
|
||||
switch (this.system.categorie) {
|
||||
case 'Alchimie': case 'Autre': case 'AlchimieAutre':
|
||||
// TODO: distinguer les remèdes alchimiques enchantables/non
|
||||
return 'alchimie'
|
||||
case 'Cuisine':
|
||||
return 'cuisine'
|
||||
case 'Remede': case 'Repos': case 'Soin':
|
||||
return 'soins'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
getProprietes() {
|
||||
const proprietes = [
|
||||
`<b>Rareté</b>: ${this.system.rarete} `,
|
||||
`<b>Catégorie</b>: ${this.system.categorie}`,
|
||||
`<b>Etat</b>: ${this.system.etat}`
|
||||
]
|
||||
const proprietesMagiques = this.system.magique ? [
|
||||
`<b>Enchantée</b> <i class="fa-solid fa-sparkles"></i> ${this.system.purifie ? ', purifiée' : ''} ${this.system.prpermanent ? 'permanente' : ''} `,
|
||||
`<b>Points de rêve</b>: ${this.system.pr}`,
|
||||
] : []
|
||||
return proprietes
|
||||
.concat(proprietesMagiques)
|
||||
.concat(this._inventaireTemplateChatData())
|
||||
.filter(it => it != undefined)
|
||||
}
|
||||
|
||||
perteReveChateauDormant() {
|
||||
if (this.system.magique && !this.system.prpermanent && this.system.pr > 0) {
|
||||
const nouveaupr = Math.max(this.system.pr - 1, 0)
|
||||
return {
|
||||
alias: this.parent.getAlias(),
|
||||
item: this,
|
||||
nouveaupr: nouveaupr,
|
||||
update: {
|
||||
_id: this.id,
|
||||
'system.pr': nouveaupr,
|
||||
'system.magique': nouveaupr > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
calculPuissance() { return this.system.herbebonus * this.system.pr }
|
||||
|
||||
static buildHerbesList(listeHerbes, max) {
|
||||
let list = {}
|
||||
for (let herbe of listeHerbes) {
|
||||
let brins = max - herbe.system.niveau;
|
||||
list[herbe.name] = `${herbe.name} (Bonus: ${herbe.system.niveau}, Brins: ${brins})`;
|
||||
}
|
||||
list['Autre'] = 'Autre (Bonus: variable, Brins: variable)'
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
@ -6,8 +6,9 @@ export class RdDItemQueue extends RdDItem {
|
||||
return "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp";
|
||||
}
|
||||
|
||||
async calculerFinPeriodeTemporel(debut) {
|
||||
async calculerFinPeriodeTemporel(timestamp) {
|
||||
// décaller le début pour calcul correct si la queue dure 12h
|
||||
const debut = timestamp.addMinutes(timestamp.indexMinute == 0 ? -1 : 0);
|
||||
return await debut.appliquerDuree(this.system.duree, this.parent);
|
||||
}
|
||||
|
||||
}
|
101
module/item/race.js
Normal file
@ -0,0 +1,101 @@
|
||||
import { ITEM_TYPES } from "../constants.js";
|
||||
import { RdDItem } from "../item.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { LIST_CARAC_PERSONNAGE, RdDCarac } from "../rdd-carac.js";
|
||||
|
||||
export class RdDItemRace extends RdDItem {
|
||||
|
||||
static get ITEM_TYPE() { return ITEM_TYPES.race }
|
||||
|
||||
static get defaultIcon() {
|
||||
return "systems/foundryvtt-reve-de-dragon/icons/humanoides/humain.webp";
|
||||
}
|
||||
|
||||
static checkRacialMax(actor, code, value) {
|
||||
const race = RdDItemRace.getRace(actor)
|
||||
if (code == LIST_CARAC_PERSONNAGE.force.code) {
|
||||
if (!race.isForceValid(actor, value)) {
|
||||
ui.notifications.warn(race.system.carac.force.limitmessage)
|
||||
return false
|
||||
}
|
||||
}
|
||||
const carac = RdDCarac.carac(code)
|
||||
if (race.isMax(actor, code, value - 1)) {
|
||||
ui.notifications.warn(`${value} est supérieure au maximum de ${carac.label}`)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
static applyRacialLimits(actor) {
|
||||
const race = RdDItemRace.getRace(actor)
|
||||
actor.system.carac.taille.value = race.getValidTaille(actor.getTaille())
|
||||
actor.system.carac.force.value = Math.min(
|
||||
actor.getForce(),
|
||||
race.getForceMax(actor))
|
||||
}
|
||||
|
||||
static isRacialMax(actor, code, value = undefined) {
|
||||
return RdDItemRace.getRace(actor).isMax(actor, code, value)
|
||||
}
|
||||
|
||||
static getRace(actor) {
|
||||
return actor.itemTypes[ITEM_TYPES.race].find(it => true) ?? RdDItemRace.getFallbackRace()
|
||||
}
|
||||
|
||||
static getFallbackRace() {
|
||||
if (RdDItemRace.fallback == undefined) {
|
||||
RdDItemRace.fallback = new RdDItemRace({ name: 'Humain', type: RdDItemRace.ITEM_TYPE })
|
||||
}
|
||||
return RdDItemRace.fallback
|
||||
}
|
||||
|
||||
|
||||
isMax(actor, code, value = undefined) {
|
||||
const path = RdDCarac.carac(code)?.path
|
||||
if (value == undefined) {
|
||||
value = path ? foundry.utils.getProperty(actor, path) : 0
|
||||
}
|
||||
if (code == LIST_CARAC_PERSONNAGE.force.code) {
|
||||
return value >= this.getForceMax(actor)
|
||||
}
|
||||
const max = foundry.utils.getProperty(this, path) ?? -1
|
||||
return (max > 0 && value >= max)
|
||||
}
|
||||
|
||||
getValidTaille(taille) {
|
||||
const min = Math.max(this.system.carac.taille.min, 0)
|
||||
if (min > taille) {
|
||||
ui.notifications.warn("La Taille est inférieur au minimum racial")
|
||||
return min
|
||||
}
|
||||
const raceMax = this.system.carac.taille.max;
|
||||
const max = raceMax < 0 ? taille + 1 : raceMax
|
||||
if (max < taille) {
|
||||
ui.notifications.warn("La Taille est supérieure au maximum racial")
|
||||
return max
|
||||
}
|
||||
return taille
|
||||
}
|
||||
|
||||
isForceValid(actor, value) {
|
||||
return value <= this.getForceMax(actor)
|
||||
}
|
||||
|
||||
getForceMax(actor) {
|
||||
const terms = this.system.carac.force.limit.replaceAll(' ', '').split('+')
|
||||
return terms.map(
|
||||
it => {
|
||||
const term = Number.parseInt(it)
|
||||
if (Number.isInteger(term)) {
|
||||
return term
|
||||
}
|
||||
const path = RdDCarac.carac(it)?.path
|
||||
if (path) {
|
||||
return foundry.utils.getProperty(actor, path)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
).reduce(Misc.sum());
|
||||
}
|
||||
}
|
@ -74,7 +74,7 @@ export class RdDRencontre extends RdDItem {
|
||||
}
|
||||
|
||||
async calculerFinPeriodeTemporel(debut) {
|
||||
return await debut.nouvelleHeure().addHeures(12);
|
||||
return debut.nouvelleHeure().addHeures(12);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ const TYPE_ITEMS_NATURELS = ["faune", "herbe", "plante", "ingredient"];
|
||||
export class RdDItemInventaireSheet extends RdDItemSheet {
|
||||
|
||||
static get defaultOptions() {
|
||||
return mergeObject(RdDItemSheet.defaultOptions, {
|
||||
return foundry.utils.mergeObject(RdDItemSheet.defaultOptions, {
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "informations" }]
|
||||
});
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
setPosition(options = {}) {
|
||||
@ -23,9 +23,10 @@ export class RdDItemInventaireSheet extends RdDItemSheet {
|
||||
|
||||
async getData() {
|
||||
const formData = await super.getData();
|
||||
return mergeObject(formData, {
|
||||
foundry.utils.mergeObject(formData, {
|
||||
milieux: await game.system.rdd.environnement.autresMilieux(this.item)
|
||||
});
|
||||
})
|
||||
return formData
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
|