Compare commits

..
Author SHA1 Message Date
VincentVk 461a398965 Police homogène pour la navigation 2025-11-27 02:08:25 +01:00
VincentVk eef0893d1a Version 13.0.20 2025-11-27 01:55:19 +01:00
VincentVk c50f1287b5 Ajustement astrologique rituels 2025-11-27 01:14:46 +01:00
VincentVk acd40f3154 Fix dépense rêve sort
La dépense de rêve de sort se faisait en parallèle de la fermeture
de fenêtre des TMRs, qui modifiait la fatigue. Du coup, l'update de
la dépense de rêve ne se faisait pas
2025-11-27 01:02:09 +01:00
VincentVk 764f9f81c8 Centrage logo pause 2025-11-26 23:39:15 +01:00
VincentVk 70e8cd74a2 Correction feuille méditation joueur 2025-11-26 21:27:39 +01:00
VincentVk e96f4e01bd Majuscule Survie en désert 2025-11-24 18:04:43 +01:00
VincentVk c44c2d7c96 Ajout d'un statut "malade/empoisonné" 2025-11-24 18:04:43 +01:00
VincentVk e2ee73bc4e Empoignade V2
Correction, de l'empoignade en mode jet V2

- le défenseur diminue le nombre de points d'empoignade
- amélioration des messages liés à l'empoignade
- ajout de choix de pertes d'endurance à infliger
2025-11-24 18:04:43 +01:00
VincentVk 3f19886342 Fix affichage sur perte d'endurance
décaller l'ajout d'effets après l'update permet
d'éviter les résultats "invisibles"
2025-11-24 18:04:43 +01:00
VincentVk 9a5afc918e Fix suppression effets 2025-11-24 18:04:43 +01:00
VincentVk 2ac35ef5d1 Corrections de styles incorrects
- combo de sélection des dommages d'empoignade
- boutons de navigation dans les journaux
- boutons de blessures dans la feuille de personnage
2025-11-24 18:04:42 +01:00
giteadmin 33c6b35601 Merge pull request '## 13.0.19 - L'introspection d'Illysis' (#784) from feature/v13-combats-v2 into v13
Release Creation / build (release) Successful in 2m10s
Reviewed-on: https, #784
2025-11-14 17:46:26 +01:00
VincentVk 82f870db05 Bouton pour jet de résistance
Ajout d'un bouton à côté de la carac rêve
2025-11-13 01:13:47 +01:00
VincentVk 878efab321 Correction expérience sur résistance 2025-11-13 00:10:08 +01:00
VincentVk 659ddbd0a4 Jet V2 - Ajout des écailles 2025-11-12 23:09:10 +01:00
VincentVk 22b9e11021 Correction particulières 2025-11-12 22:21:27 +01:00
VincentVk 02ec8880fc Correction combat V2 avec plusieurs joueurs
Les messages de défense fonctionnent sur les jets V2
2025-11-12 22:10:51 +01:00
VincentVk 521cf50b7b Pas de suppression surenc/demireve
L'icône surencombrement ne peut plus être supprimée si on est
sur-encombré.
2025-11-12 22:10:51 +01:00
VincentVk 1cc6fab3a9 Autoriser attaque sans initiative 2025-11-12 22:10:51 +01:00
VincentVk 7baccbabb9 Gestion des droits jets V2 2025-11-12 22:10:42 +01:00
giteadmin d9b24b0f97 Correction sur changelog
Release Creation / build (release) Successful in 2m37s
2025-11-12 15:21:43 +01:00
giteadmin d504a0e131 Merge pull request '13.0.17 - Le reflet d'Illysis' (#783) from feature/v13-mineurs into v13
Reviewed-on: https, #783
2025-11-12 15:19:43 +01:00
VincentVk 09ca86a7fd Suppression de message d'erreur
Si un acteur n'a pas toutes les compétences (ie: invocation), les
messages indiquant que les compétences sont manquantes ne
sont plus affichés
2025-11-11 23:09:28 +01:00
VincentVk 5b68837023 Ajout icone service écuries 2025-11-11 23:09:28 +01:00
VincentVk 7452c54c04 Feuille personnage avec police 2025-11-11 23:09:28 +01:00
giteadmin af1976b9d8 Update release script
Release Creation / build (release) Successful in 1m32s
2025-11-08 00:44:16 +01:00
giteadmin 9fe45ce99f Update release script
Release Creation / build (release) Failing after 1m14s
2025-11-08 00:33:26 +01:00
giteadmin 852964e77b Update release script
Release Creation / build (release) Failing after 1m32s
2025-11-08 00:29:16 +01:00
giteadmin b87dea1661 Update release script
Release Creation / build (release) Failing after 2m22s
2025-11-08 00:24:27 +01:00
giteadmin d2835c7472 Update release script
Release Creation / build (release) Failing after 52s
2025-11-08 00:22:18 +01:00
giteadmin f3c58424e5 Update release script
Release Creation / build (release) Failing after 5s
2025-11-08 00:06:19 +01:00
giteadmin c600eb3965 Update release script
Release Creation / build (release) Has been cancelled
2025-11-08 00:04:57 +01:00
giteadmin 4a7848cb04 Fix other CSS dakr/light theme issues
Release Creation / build (release) Has been cancelled
2025-11-08 00:02:51 +01:00
giteadmin 0d62b60e38 Merge pull request 'v13.0.16 - La paix d'Illysis' (#782) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
Reviewed-on: https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/pulls/782
2025-11-02 09:55:25 +01:00
VincentVk 9b91850731 Export de personnage en pdf
Première version d'export de personnage pdf
2025-11-01 01:28:44 +01:00
VincentVk 05c7a91f93 Correction d'un problème à l'ouverture
Pour un personnage saisis dans d'anciennes versions avec un sort
de coût entier, la feuille de personnage ne pouvait pas s'ouvrir
2025-11-01 00:44:26 +01:00
VincentVk f83fdb3b8f Fix: fenêtre jets V2 hors combat
la fenêtre ne marchait pas hors d'un combat
2025-10-29 02:03:43 +01:00
giteadmin 020ff4b014 Merge pull request 'v13.0.15 - Les pièces d'Illysis' (#781) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
Reviewed-on: https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/pulls/781
2025-10-28 18:43:25 +01:00
VincentVk b3c7453823 Fix achat dans les commerces 2025-10-28 17:57:27 +01:00
VincentVk 18d003aa5d Fix colors of tabs and lists in interface
These colors where misbehaving in dark/light themes
2025-10-28 17:57:27 +01:00
giteadmin 0b90badb5e Merge pull request 'v13.0.14 - Le familier d'Illysis' (#779) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
Reviewed-on: https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/pulls/779
2025-10-25 23:21:59 +02:00
VincentVk 290b5029d1 Correction couleurs sommaires 2025-10-24 22:20:29 +02:00
VincentVk a7e4aea52d Fix: meditation V2 2025-10-24 01:22:20 +02:00
VincentVk 755d15509e Ajout du StatusEffect surencombré 2025-10-23 20:21:56 +02:00
VincentVk 02cea84ebb Empoignade V2 2025-10-23 12:01:52 +02:00
VincentVk c47fc4f5b6 Fix scenes image locations 2025-10-22 22:40:07 +02:00
VincentVk 147e49f2cb Gestion des significatives 2025-10-21 01:40:14 +02:00
VincentVk 7f4f942d50 Amélioration des entités
- l'attaquant ne sait plus que c'est une entité de cauchemar (surprise!)
- l'encaissement indique une blessure dans le tchat... même si ce
  n'est que de l'endurance
- les blurettes suivent les règles des entités de cauchemar (p322)
2025-10-21 01:39:23 +02:00
VincentVk 8f4df1af56 Fix: ajustements surprises
Affichage de l'image de la surprise
2025-10-21 01:39:23 +02:00
VincentVk 77f2de2c5f Jet V2 pour les créatures 2025-10-21 01:39:16 +02:00
VincentVk e5e271e424 Corrections majuscules/couleurs 2025-10-19 23:53:43 +02:00
giteadmin 43ecca8be1 Merge pull request 'v13.0.13 - L'épanouissement d'Illysis' (#777) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
Reviewed-on: https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/pulls/777
2025-10-18 18:04:36 +02:00
VincentVk e21f7e398a Création de tâches dans la fenêtre de jets 2025-10-18 00:52:14 +02:00
VincentVk e16f89743a Affichage des ajustements V2 2025-10-18 00:52:14 +02:00
VincentVk a6c593c100 Corrections premiers retours 2025-10-18 00:52:14 +02:00
giteadmin cd8e190082 Merge pull request 'v13.0.12 - La méditation d'Illysis' (#776) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
Reviewed-on: https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/pulls/776
2025-10-16 20:14:03 +02:00
VincentVk f2106763c1 v13.0.12 2025-10-16 00:55:58 +02:00
VincentVk 5da5cb0314 Gestion des maladresses 2025-10-16 00:35:43 +02:00
VincentVk 6d7f66569a Lancer de sorts V2 2025-10-15 22:42:14 +02:00
VincentVk 3e8963b20b Impacts uniquement sur l'acteur 2025-10-15 22:42:14 +02:00
VincentVk 2cf5b06da8 Correction: rename bringToTop 2025-10-15 22:42:13 +02:00
VincentVk 68c01fc930 Montée TMR sur méditation
ajout d'un bouton pour aller dans les TMR lors d'une
méditation réussie
2025-10-15 22:42:13 +02:00
VincentVk 3bc1c4871b Biugfix: compétences de jeu
Les compétences de jeu spécifiques (doublon) ne remplacent plus
la compétence active si le jet n'est pas un jet de jeu
2025-10-15 00:26:01 +02:00
VincentVk 3d732e9a8a Suppression des signes draconiques
en cas de descente des TMR, suppression des signes
draconiques éphémères durant seulement 1 round
2025-10-15 00:24:35 +02:00
VincentVk 35f226af5c Correction du générateur aléatoire
- couleurs de cheveux/yeux
- les tailles entre 1m00 et 1m09 sont correctement affichées
- possibilité de positionner le sexe masculin/féminin en un clic
2025-10-14 17:44:39 +02:00
giteadmin 126a0701d8 Merge pull request 'v13.0.11 - Le gambit d'Illysis' (#775) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
Reviewed-on: https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/pulls/775
2025-10-09 14:14:44 +02:00
VincentVk edf920b340 Roll V2: cuisine 2025-10-08 16:36:14 +02:00
VincentVk 293af5ab83 Roll V2: les jeux 2025-10-08 16:35:58 +02:00
VincentVk 1bf9e330f4 Petites améliorations 2025-10-05 22:39:08 +02:00
giteadmin 33dc58138c Merge pull request '13.0.10 - Les papilles d'Illysis' (#774) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
Reviewed-on: https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/pulls/774
2025-10-05 21:39:20 +02:00
VincentVk fa6769fcd7 Fenêtres Roll V2
Maintenant disponibles pour:
- méditation
- tâches
- soins
2025-10-05 03:09:52 +02:00
VincentVk 47c4478303 Roll V2 sur compétences&combat
Corrections associées
Maintenant, active en mode rollV2
2025-10-03 22:34:07 +02:00
VincentVk 52065fd6f6 changelog 13.0.10 2025-10-03 02:21:22 +02:00
VincentVk 6886f19921 Jet de compétence V2 2025-10-03 02:21:22 +02:00
VincentVk 10a89cc268 Fix regression table rdd 2025-10-03 02:21:22 +02:00
VincentVk 6a987086f8 Correction message init & pugilat 2025-10-03 02:21:22 +02:00
VincentVk 54f470d531 Roll recette de cuisine 2025-10-03 02:21:22 +02:00
VincentVk 37af0dd4f1 Rename ajustements => v1 2025-10-03 02:21:22 +02:00
VincentVk d46b039a63 Ajout des saignements 2025-10-03 02:21:21 +02:00
VincentVk 7370b633db Gestion attaques v2 et initiative 2025-10-03 02:21:21 +02:00
VincentVk d0ba1ebf99 utilisation de renderTemplate "interne"
Import de foundry.applications.handlebars.renderTemplate
au travers d'une constante pour éliminer les warnings
2025-09-30 02:04:53 +02:00
VincentVk 053bc23d12 Move HUD button attaque 2025-09-29 01:47:35 +02:00
giteadmin 1360992daa Minot fixes 2025-09-28 22:12:23 +02:00
giteadmin 878645491d Merge pull request 'v13.0.9 - corrections' (#773) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
Reviewed-on: https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/pulls/773
2025-09-28 22:10:05 +02:00
VincentVk edfaf203f7 Colonne dmg dans onglet combat 2025-09-28 22:00:05 +02:00
VincentVk 3480b64d75 Fix competencecreatures/competences 2025-09-28 22:00:05 +02:00
giteadmin 17e10d3be9 Merge pull request 'v13.0.9 - Le combat d'Illysis' (#772) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
Reviewed-on: https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/pulls/772
2025-09-28 17:39:55 +02:00
VincentVk bbcd6ad363 Fin de gestion encaissement/recul V2 2025-09-28 17:21:59 +02:00
VincentVk faca73b0a1 RollV2, tchat et appel chance
gestion des appels à la chance pour tout jet V2

correction de soucis forçage du jet

continuation des messages de défense
2025-09-28 17:19:34 +02:00
VincentVk a7e14736e4 Amélioration espace boutons actions 2025-09-28 17:19:34 +02:00
VincentVk 2741fc3fbf Avancement messages défense & oeuvres 2025-09-27 01:43:49 +02:00
giteadmin 160f10a639 Merge pull request 'v13' (#771) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
Reviewed-on: https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/pulls/771
2025-09-26 10:54:39 +02:00
VincentVk d26ab59c51 Nouvelle fenêtre: attaque/defense
quelques améliorations
préparation pour gérer les messages de résultats en
fonction du type de jet (attaque/compétence/...)

quelques corrections (suppression du filtre de compétences
quand on change de type de jet, astrologie, ..)
2025-09-24 22:39:25 +02:00
VincentVk 1f330c734e Clarification des maladresses 2025-09-24 22:39:25 +02:00
VincentVk 74515d28f4 Amélioration de la gestion de la surprise 2025-09-24 22:39:25 +02:00
giteadmin c84af21c7e Merge pull request 'v13' (#770) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
Reviewed-on: https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/pulls/770
2025-09-22 11:24:07 +02:00
VincentVk 0730bdf240 Nouveau roll-dialog: mode attaque / defense 2025-09-22 02:25:47 +02:00
VincentVk 607eedc6d2 Fix montée TMR 2025-09-21 00:15:36 +02:00
286 changed files with 87015 additions and 2700 deletions
+55 -56
View File
@@ -6,71 +6,70 @@ on:
jobs:
build:
runs-on: ubuntu-latest
runs-on: localhost
steps:
- run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner."
- run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner."
#- uses: actions/checkout@v3
- uses: RouxAntoine/checkout@v3.5.4
with:
ref: 'v13'
- name: Add NODE/NPM bin directory to PATH
shell: bash
run: echo "/opt/alt/alt-nodejs20/root/usr/bin/" >> $GITHUB_PATH
# get part of the tag after the `v`
- name: Extract tag version number
id: get_version
uses: battila7/get-version-action@v2
- uses: RouxAntoine/checkout@v3.5.4
with:
ref: "v13"
# 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
# get part of the tag after the `v`
- name: Extract tag version number
id: get_version
uses: battila7/get-version-action@v2
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '18' # Use the node version your project requires
# 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://gitea.scriptarium.org/${{gitea.repository}}
manifest: https://gitea.scriptarium.org/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/system.json
download: https://gitea.scriptarium.org/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/rddsystem.zip
- name: Install dependencies
run: npm install
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: "18" # Use the node version your project requires
- name: Build the compendiums
run: node ./tools/packCompendiumsToDist.mjs
- name: Install dependencies
run: npm install
# Create a zip file with all files required by the module to add to the release
- run: |
apt update -y
apt install -y zip
- name: Build the compendiums
run: node ./tools/packCompendiumsToDist.mjs
- run: zip -r ./rddsystem.zip system.json template.json README.md LICENSE.txt assets/ css/ fonts/ icons lang/ module/ packs/ pic/ sounds/ styles/ templates/
- name: Create ZIP file
run: zip -r ./rddsystem.zip system.json template.json README.md LICENSE.txt assets/ css/ fonts/ icons lang/ module/ packs/ pic/ sounds/ styles/ templates/
- name: setup go
uses: actions/setup-go@v3
with:
go-version: '>=1.20.1'
- 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: Use Go Action
id: use-go-action
uses: https://gitea.com/actions/release-action@main
with:
files: |-
./rddsystem.zip
system.json
api_key: "${{secrets.RDD_PUBLISH_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/v13/changelog.md'
compatibility-minimum: '13'
compatibility-verified: '13'
- name: Publish to Foundry server
uses: djlechuck/foundryvtt-publish-package-action@v1
with:
token: ${{ secrets.RDD_PUBLISH_RELEASE_FOUNDRY }}
id: "foundryvtt-reve-de-dragon"
version: ${{github.event.release.tag_name}}
manifest: "https://gitea.scriptarium.org/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/system.json"
notes: "https://gitea.scriptarium.org/Scriptarium/foundryvtt-reve-de-dragon/raw/branch/v13/changelog.md"
compatibility-minimum: "13"
compatibility-verified: "13"
+7 -4
View File
@@ -12,8 +12,8 @@ Pseudo : LeRatierBretonnien
Mainteneur/Développeur : LeRatierBretonnien
Développeur : VincentVk
Tests, Compendiums, Données: Fred, Fab, Grendel
Styles/CSS : Mandar
Tests, Compendiums, Données: Fred, Fab, Grendel, LeRatierBretonnien, VincentVk
Styles/CSS : Mandar, VincentVk
# Mentions Légales
@@ -23,6 +23,9 @@ La carte des Terres Médianes du Rêve est une illustration de **Jidus**, utilis
Les silhouettes des créatures, humanoïdes et entités sont des illustrations de **Roland Barthélémy**, et sont utilisés dans le cadre de ce projet avec son aimable autorisation.
Merci à eux !!
Toute la propriété intellectuelle leur appartient, ce système est une adpatation destinée à fonctionner sous FoundryVTT.
Toute la propriété intellectuelle leur appartient, ce système est une adaptation destinée à fonctionner sous FoundryVTT.
L'ensemble du code est sous licence Creative Commons.
L'ensemble du code est sous licence Creative Commons.
# Licences
- L'export pdf utilise la librairie [pdf-lib](https://pdf-lib.js.org/) sous licence [MIT](pdf-lib-LICENSE.md)
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><defs><linearGradient x1="0" x2="1" y1="1" y2="0" id="lorc-shattered-sword-gradient-4"><stop offset="0%" stop-color="#4a4a4a" stop-opacity="1"></stop><stop offset="100%" stop-color="#c9c9c9" stop-opacity="1"></stop></linearGradient><radialGradient id="lorc-shattered-sword-gradient-5"><stop offset="0%" stop-color="#9013fe" stop-opacity="1"></stop><stop offset="100%" stop-color="#85562c" stop-opacity="1"></stop></radialGradient><radialGradient id="lorc-shattered-sword-gradient-7"><stop offset="0%" stop-color="#9013fe" stop-opacity="1"></stop><stop offset="100%" stop-color="#85562c" stop-opacity="1"></stop></radialGradient></defs><g class="" transform="translate(1,-2)" style=""><path d="m496.223 16.818-48.475 44.205 48.475 4.575v-48.78zm-41.55 1.22-68.91 11.28-7.04 65.547 75.95-76.828zM352.26 77.907l-87.887 50.3 15.447 41.026 82.662-16.87-10.222-74.456zm64.34 25.022-32.967 67.443 24.842 70.684 54.314-134.19-46.19-3.937zm-271.362 72.808c-10.02.155-20.714 3.165-30.79 9.057 4.143 8.863 3.382 18.708-2.776 24.873-6.158 6.165-15.993 6.927-24.846 2.78-12.923 22.167-11.88 47.34 2.485 61.73l29.84-29.87c58.655 42.87 109.37 92.94 150.57 151.24l-36.19 36.23 6.61-6.604c14.283 14.298 39.192 15.42 61.23 2.732-4.88-9.197-4.366-19.74 2.107-26.22 6.47-6.478 17-6.993 26.185-2.112 12.66-22.062 11.54-47-2.732-61.3l-28.248 28.28c-57.035-42.41-107.91-92.665-151.426-150.386l35.455-35.492-6.61 6.603c-7.834-7.843-18.863-11.726-30.862-11.542zm108.45 4.512c-17.61 17.41-39.674 39.21-62.22 61.375a728.952 728.952 0 0 0 27.407 30.094l59.063-59.126-24.25-32.344zm78.28 32.688L297 219.968l-65 65.063a728.12 728.12 0 0 0 35 32.376c22.02-23.134 43.764-46.41 64.97-69.406v-35.063zM173.47 313.25c-31.146 40.858-67.877 74.323-108.905 101.875 4.13 13.708 16.394 26.374 30.624 30.563 29.466-41.26 61.113-79.902 100.97-109.97a637.777 637.777 0 0 0-22.688-22.468zM44.5 410.28l-20.844 20.845c7.133 24.65 27.843 44.912 53.72 53.438l19.28-19.313c-26.948-4.28-48.314-26.91-51.875-52.938l-.28-2.03z" fill="#fff" fill-opacity="1" transform="translate(51.2, 51.2) scale(0.8, 0.8) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><g class="" transform="translate(0,0)" style=""><path d="m329.5 29.12-8.1 11.4L359 67.16l8.1-11.44zm-88 5.04 24.2 45.36 1.8 1.29 14.8-40.36zm57.6 12.63-16.4 44.8 40.7 28.81 35.3-31.54c-.9-.58-1.9-1.19-2.8-1.84zM59.83 48.56l10.84 45.83 29.63 2.6 2.7-29.63zM470.9 75.41c-5.6 4.71-12.2 8.59-19.5 11.74 5 46.45-14.7 83.45-45.2 109.75-26.5 22.9-60.9 38.4-95 47.9-2.5 4.8-5 9.2-7.4 13.1 41.5 5.4 93.2-21.2 129.2-60 19.8-21.3 34.8-45.9 41.1-69.2 5.2-19.4 4.7-37.42-3.2-53.29zm-351.3 8.71-3 32.48-32.35-2.9 226.55 271 20-16.7 15.3-12.8zM434 93.09c-4.2 1-8.5 2-12.8 2.7-14.9 2.5-30.1 3.1-43.5.3l-41 36.61c4 7 5 15.7 4.5 24.5-.6 12.6-4.3 26.7-9.3 40.9-3 8.3-6.3 16.6-9.9 24.6 26.9-9.2 52.6-22.3 72.5-39.4 26.2-22.8 42.5-51.6 39.5-90.21zM274 107.4l-51.2 72.2 30.6 36.5 58.2-82.1zM173.8 248.8 34.53 445.2l37.53 26.6L204.3 285.3zm233 79.2L273.3 439.5l19.2 23.1L426 351zm-18.3 77.9-35.3 29.4 39.7 47.6 35.3-29.4z" fill="#fff" fill-opacity="1"></path></g></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

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

After

Width:  |  Height:  |  Size: 2.1 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><g class="" transform="translate(0,0)" style=""><path d="M243.512 23.29c-27.105 18.337-53.533 32.92-82.274 45.337-2.843 17.364-3.948 34.497-4.05 51.584 28.913 15.41 56.096 32.85 83.33 49.634l7.045 4.344-3.432 7.482c-12.12 26.572-24.33 47.087-46.245 70.3l-5.184 5.512-6.46-3.904c-32.974-19.974-74.472-38.724-113.373-53.95l6.826-17.374c36.79 14.4 75.11 32.32 108.153 51.504 15.396-17.198 25.326-33.354 34.713-52.89-43.44-26.91-86.13-53.51-134.69-70.632-23.012 20.357-37.705 45.243-51.942 70.74 8.324 25.495 6.596 53.376-6.596 77.46 48.58-.593 97.994 2.23 150.666 10.26l5.658.837 1.787 5.44c8.85 26.46 11.79 54.41 8.325 83.588l-.987 8.432-8.466-.187c-40.508-.864-80.175-2.138-118.17.234 1.634 15.94-2.31 30.972-7.724 45.025 13.427 28.54 27.38 55.8 48.29 79.39 41.27-19.05 73.564-31.288 115.93-42.85-3.407-13.72-6.918-26.36-11.097-33.62-5.122-8.9-10.207-13.057-17.85-15.256-15.284-4.4-44.533 2.293-92.894 19.454l-6.243-17.594c48.907-17.354 79.702-26.894 104.283-19.82 9.133 2.628 16.884 8.004 23.066 15.46 14.487-7.627 28.415-16.79 42.053-26.996 12.34-45.92 37.29-81.42 66.626-112.107-7.226-13.52-13.208-27.204-20.563-40.613l-3.394-6.168 5-4.965c23.275-23.13 47.34-40.157 71.87-52.487l8.395 16.716c-20.952 10.53-41.503 25.913-61.795 45.152 12.41 23.91 22.263 45.5 39.457 64.826 37.488-27.124 74.943-51.39 116.84-74.938-13.96-30.473-31.345-58.357-56.286-79.462-32.2 13.38-62.527 17.39-92.61 12.29-14.223 13.25-30.094 22.23-48.756 23.337-29.017 1.722-60.74-15.74-99.174-57.672l6.858-6.295.017-.028.006.006 6.88-6.314c36.702 40.043 63.74 52.87 84.32 51.65 18.514-1.1 35.03-14.95 51.684-35.406-28.827-31.81-64.174-59.94-97.822-84.465zM39.324 277.884c-6.06.022-12.104.098-18.142.223 1.673 26.288 5.512 51.288 14.052 73.732 45.88-5.82 93.308-4.96 141.15-3.87 1.518-21.27-.253-41.69-6.058-61.212-45.528-6.565-88.59-9.03-131.002-8.873z" fill="#fff" fill-opacity="1"></path></g></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

+66
View File
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 410.39459 390.34079"
version="1.1"
id="svg6"
sodipodi:docname="encaisser.svg"
width="410.39459"
height="390.34079"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2284"
inkscape:window-height="1517"
id="namedview8"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="1.4355469"
inkscape:cx="206.1036"
inkscape:cy="215.2477"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg6" />
<g
class=""
transform="translate(-49.8964,-68.7523)"
id="g4">
<path
d="m 26.996,47.947 c 11.726,44.806 56.176,129.96 67.496,242.934 -6.597,76.494 -22.66,98.81 -22.66,152.74 0,27.602 11.33,38.038 23.254,38.038 11.662,0 23.72,-11.823 23.72,-40.896 0,-56.606 -16.937,-73.84 -23.283,-151.65 6.472,-83.65 59.715,-45.933 59.715,2.765 0,-112.652 101.99,-85.16 116.024,-34.77 -5.164,35.11 -15.028,45.947 -15.028,75.368 0,16.633 8.51,28.86 16.74,28.86 8.416,0 16.41,-11.433 16.41,-27.226 0,-27.953 -9.303,-41.066 -14.515,-75.825 15.447,-37.68 115.544,-34.583 115.845,-1.754 -3.41,26.414 -12.764,32.13 -12.764,51.16 0,9.714 6.58,16.855 12.943,16.855 6.506,0 12.685,-6.677 12.685,-15.9 0,-18.435 -9.164,-25.838 -12.596,-52.854 14.138,-49.16 86.57,-19.867 92.008,-73.298 -51.22,45.91 -357.175,26.76 -455.994,-134.545 z m 128.85,266.22 c -4.676,31.802 -17.635,40.28 -17.635,61.724 0,10.642 8.592,18.346 17.636,18.346 8.844,0 17.988,-8.24 17.988,-19.45 0,-22.338 -13.464,-28.757 -17.988,-60.62 z"
fill="#ffffff"
transform="matrix(0.9,0,0,0.9,25.6,25.6)"
fill-opacity="1"
id="path2" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><defs><linearGradient x1="0" x2="1" y1="1" y2="0" id="delapouite-sparkles-gradient-4"><stop offset="0%" stop-color="#4a4a4a" stop-opacity="1"></stop><stop offset="100%" stop-color="#c9c9c9" stop-opacity="1"></stop></linearGradient><radialGradient id="delapouite-sparkles-gradient-5"><stop offset="0%" stop-color="#9013fe" stop-opacity="1"></stop><stop offset="100%" stop-color="#85562c" stop-opacity="1"></stop></radialGradient><radialGradient id="delapouite-sparkles-gradient-7"><stop offset="0%" stop-color="#9013fe" stop-opacity="1"></stop><stop offset="100%" stop-color="#85562c" stop-opacity="1"></stop></radialGradient></defs><g class="" transform="translate(1,-2)" style=""><path d="M237.4 20.73c-6.1 42.1-26.8 64.2-63.9 64 31.6 4.5 63.8 8 63.9 64.07-.6-46.1 24.5-63.07 64.1-64.07-38-1.5-64.9-16.3-64.1-64zm127.8 11.58c-9.1 14.25-20.8 21.29-38.9 10.28 14.9 11.79 18.6 24.76 10.2 38.97 8.9-11.18 17.5-22.73 39-10.27-17.8-10.06-18.8-23.57-10.3-38.98zM59.68 41.69c-2.7 18.8-12 28.6-28.5 28.5 14.1 2 28.4 3.6 28.5 28.52-.3-20.5 10.9-28.12 28.5-28.52-16.9-.7-28.9-7.3-28.5-28.5zM431 66.28c-2.7 18.8-12 28.6-28.5 28.5 14.1 2 28.4 3.6 28.5 28.52-.3-20.5 10.9-28.12 28.5-28.52-16.9-.7-28.9-7.3-28.5-28.5zM120.3 116.4c-15.8 53.7-47.76 48-79.35 43.4C76.6 170 90.3 197.1 84.28 239.2c12.66-46 42.62-52.6 79.42-43.4-37.6-12.1-56.9-35.4-43.4-79.4zm187 5c-8.8 61.6-39.3 94-93.6 93.7 46.2 6.5 93.6 11.7 93.6 93.7-.8-67.3 35.9-92.2 93.8-93.7-55.5-2.2-94.9-23.9-93.8-93.7zm136.8 38.3c-13.1 21.6-29.5 28.8-49.7 20.1 16.3 9.7 33 19.1 20.1 49.6 10.3-25.2 27.9-28.7 49.7-20-20.3-9.7-31.6-23.9-20.1-49.7zM50.7 243.2c9.16 16.7 7.63 30.1-5.61 40 12.46-6.9 24.85-14.3 39.91 5.6-12.57-16.2-8.2-29 5.61-40-13.92 9.7-27.47 11.6-39.91-5.6zm137.2.3c11.4 26.8-.5 41.3-21.7 50.9 22.7-8.5 40.8-4.5 50.9 21.7-12.7-31.8 4.8-41.2 21.7-50.9-21 8.5-37.8.9-50.9-21.7zm228 12.6c-26.6 64.7-68.7 91.7-127.8 76.4 48.6 19.8 98.8 38.5 76.4 127.9 17.5-73.7 64.4-90.7 127.9-76.5-59.9-17.5-96.9-52-76.5-127.8zM99.94 295.5c15.66 57.8.86 98.1-47.32 118.5 43.46-11.8 87.38-25.2 118.68 47.4-26.4-59.3-3.4-95.4 47.3-118.8-50 19.2-93.1 15-118.66-47.1zm169.36 61c-21.8 20.6-43 23.6-63.2 7.3 15.5 16.3 31.6 32.4 7.2 63.3 19.8-25.6 41.2-24.1 63.3-7.3-20.2-17.4-28.6-37.5-7.3-63.3zM443.2 404c-2.7 18.8-12 28.6-28.5 28.5 14.1 2 28.4 3.6 28.5 28.5-.3-20.5 10.9-28.1 28.5-28.5-16.9-.7-28.9-7.3-28.5-28.5zm-169.7 36c-2.7 18.8-12 28.6-28.5 28.5 14.1 2 28.4 3.6 28.5 28.5-.3-20.5 10.9-28.1 28.5-28.5-16.9-.7-28.9-7.3-28.5-28.5z" fill="#fff" transform="translate(51.2, 51.2) scale(0.8, 0.8) rotate(0, 256, 256) skewX(0) skewY(0)" fill-opacity="1"></path></g></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><g class="" transform="translate(0,0)" style=""><path d="M256.25 20.313c-108.64 0-196.78 90.592-196.78 202.937 0 84.615 49.994 156.904 121.093 187.438v-16.375c0-25.638-6.2-40.132-13.875-48.47-7.675-8.336-17.567-11.4-27.72-11.937-18.252-.97-32.4-12.266-40.905-27-6.47-11.205-5.975-24.767-.532-36.97 5.444-12.2 15.49-23.71 29.19-33.905 27.394-20.39 69.79-35.56 122.436-35.56 52.702 0 98.475 15.648 129.344 36.218 15.435 10.284 27.24 21.746 34.22 33.968 6.976 12.222 8.93 26.41 2.186 38.094-4.19 7.257-11.026 11.988-18.687 15.938-7.663 3.95-16.085 6.78-24.595 6.78-11.865 0-20.63 2.214-27.438 10.157s-12.437 23.63-12.437 52.688v16.437c71.195-30.488 121.28-102.814 121.28-187.5 0-112.347-88.14-202.938-196.78-202.938zm-76.656 86.718c1.53.02 3.05.078 4.562.157 14.525.766 28.29 4.3 41.063 9.97l17.31 7.687-16.624 9.062-84.062 45.875-8.938-16.405 65.156-35.563c-24.195-5.513-50.92-1.877-82.062 17.532l-9.875-15.844c25.778-16.066 50.528-22.75 73.47-22.47zm150.312 0c22.944-.28 47.722 6.404 73.5 22.47l-9.875 15.844c-31.14-19.41-57.865-23.045-82.06-17.53l65.155 35.56-8.938 16.407-84.062-45.874L267 124.844l17.313-7.688c12.772-5.67 26.506-9.203 41.03-9.97 1.514-.078 3.034-.136 4.563-.155zm-73.594 170.282c-68.947 0-113.104 15.367-116.843 37.907l.5.03c13.487.714 28.843 5.31 40.468 17.938 11.624 12.627 18.812 32.418 18.812 61.125v100.312h113.813V394.312c0-31.4 5.766-51.81 16.937-64.843 11.17-13.034 27.003-16.69 41.625-16.69.352 0 .76-.03 1.156-.06-6.417-22.614-49.872-35.408-116.467-35.408z" fill="#fff" fill-opacity="1"></path></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

+65
View File
@@ -0,0 +1,65 @@
<?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 448 434"
version="1.1"
id="svg6"
sodipodi:docname="surenc.svg"
width="448"
height="434"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="3840"
inkscape:window-height="2054"
id="namedview8"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="1.4355469"
inkscape:cx="224"
inkscape:cy="210"
inkscape:window-x="-11"
inkscape:window-y="-11"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<g
class=""
id="g4"
transform="translate(-32,-46)">
<path
d="m 256,46 c -45.074,0 -82,36.926 -82,82 0,25.812 12.123,48.936 30.938,64 H 128 L 32,480 H 480 L 384,192 H 307.062 C 325.877,176.936 338,153.812 338,128 338,82.926 301.074,46 256,46 Z m 0,36 c 25.618,0 46,20.382 46,46 0,25.618 -20.382,46 -46,46 -25.618,0 -46,-20.382 -46,-46 0,-25.618 20.382,-46 46,-46 z m -82.215,202.95 h 23.5 v 33.263 l 33.873,-33.264 h 27.283 l -43.883,43.15 48.4,47.974 H 233.54 l -36.255,-35.888 v 35.888 h -23.5 z m 119.934,21.24 c 4.76,0 8.952,0.934 12.573,2.806 3.62,1.872 6.938,4.82 9.95,8.85 v -10.13 h 21.972 v 61.462 c 0,10.986 -3.48,19.368 -10.438,25.146 -6.917,5.82 -16.968,8.727 -30.152,8.727 -4.272,0 -8.4,-0.325 -12.39,-0.976 a 77.367,77.367 0 0 1 -12.024,-2.99 v -17.03 c 3.826,2.198 7.57,3.826 11.23,4.884 3.664,1.098 7.347,1.648 11.05,1.648 7.162,0 12.41,-1.566 15.746,-4.7 3.337,-3.132 5.006,-8.035 5.006,-14.708 v -4.7 c -3.01,3.986 -6.328,6.916 -9.95,8.788 -3.62,1.87 -7.813,2.808 -12.573,2.808 -8.343,0 -15.238,-3.275 -20.69,-9.826 -5.453,-6.592 -8.18,-14.974 -8.18,-25.146 0,-10.214 2.727,-18.576 8.18,-25.086 5.452,-6.55 12.347,-9.827 20.69,-9.827 z m 8.118,15.746 c -4.517,0 -8.038,1.67 -10.56,5.005 -2.523,3.338 -3.784,8.058 -3.784,14.162 0,6.266 1.22,11.026 3.662,14.28 2.442,3.215 6.003,4.823 10.682,4.823 4.557,0 8.096,-1.67 10.62,-5.006 2.522,-3.337 3.784,-8.036 3.784,-14.098 0,-6.104 -1.262,-10.824 -3.785,-14.16 -2.523,-3.337 -6.062,-5.006 -10.62,-5.006 z"
fill="#ffffff"
fill-opacity="1"
id="path2" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

+66
View File
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 323.9906 329.83231"
version="1.1"
id="svg6"
sodipodi:docname="weak.svg"
width="323.9906"
height="329.83231"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2230"
inkscape:window-height="1388"
id="namedview8"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="1.4355469"
inkscape:cx="157.6092"
inkscape:cy="192.4342"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg6" />
<g
class=""
transform="translate(-98.3908,-91.5658)"
id="g4">
<path
d="M 200.094,21.094 213.969,164.814 83.72,58.343 156.344,198.249 78.624,168.779 112.906,230.905 30.844,228.843 135.874,297 31.75,327.03 141.188,348.188 c 8.39,-48.802 49.597,-85.194 97.75,-105.344 28.916,-12.1 60.67,-18.762 90.75,-18.594 19.237,0.108 37.776,3.024 54.437,9.063 l 48,-119.375 L 350,196.5 369.22,34.72 327.344,130.688 313.47,92.03 l -32.69,83.5 z m 255.78,190.687 c -17.883,-0.093 -38.852,9.04 -55.937,26.126 a 100.103,100.103 0 0 0 -13.562,16.875 C 357.123,237.155 314,237.977 273.095,250.877 c -9.17,2.484 -18.214,5.537 -26.94,9.188 -43.676,18.277 -78.503,49.837 -86.218,89.625 -6.61,30.108 5.37,63.223 47.438,94.843 H 88.062 l -26.437,47.75 H 318.78 l -88.467,-103.25 c 24.27,-26.707 67.457,-43.703 97,-45.06 13.792,45.096 36.233,113.496 71.718,148.31 h 60.876 c -43.07,-46.546 -76.57,-109.087 -81.97,-179.842 a 33.579,33.579 0 0 0 6.314,8.78 c 18.664,18.664 55.945,11.618 83.28,-15.718 27.337,-27.336 34.384,-64.618 15.72,-83.28 -7,-7 -16.645,-10.382 -27.375,-10.44 z"
fill="#ffffff"
fill-opacity="1"
transform="matrix(0.7,0,0,0.7,76.8,76.8)"
id="path2" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

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

After

Width:  |  Height:  |  Size: 7.6 KiB

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

After

Width:  |  Height:  |  Size: 4.1 KiB

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

After

Width:  |  Height:  |  Size: 1.1 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><g class="" transform="translate(0,0)" style=""><path d="M221.313 16a23.682 23.695 0 0 0-23.688 23.688v106.406a23.682 23.695 0 0 0 2.156 9.72 23.682 23.695 0 0 0 3.157 13.81l41.75 71.626-79 55.438 6.094-48.625a23.682 23.695 0 0 0-8.186-20.97l-66.28-81.937a23.682 23.695 0 0 0-33.314-3.5l-9.188 7.438a23.682 23.695 0 0 0-3.53 33.344l59.78 73.906-11.25 89.937a23.682 23.695 0 0 0 12.47 23.876l37.468 53.47a23.695 23.682 1.57 0 0 2.344 2.812 23.682 23.695 0 0 0 13.594 20.062L262 491.53a23.682 23.695 0 0 0 9.97 2.22 23.682 23.695 0 0 0 23.53-2.063l87.156-60.937a23.682 23.695 0 0 0 5.844-33l-6.78-9.688a23.682 23.695 0 0 0-32.97-5.875l-72.406 50.657-59.063-27.625 120.595-84.626a23.695 23.682 1.57 0 0 5.53-5.5 23.682 23.695 0 0 0 14.626-13.594l37.22-91.53 87.813-44.845a23.694 23.682 1.18 0 0 10.312-31.875L488 122.687a23.694 23.682 1.18 0 0-31.875-10.343l-94.688 48.375a23.694 23.682 1.18 0 0-9.843 9.436 23.682 23.695 0 0 0-8.344 10.47l-27.375 67.31-5.22-7.436a23.682 23.695 0 0 0-3-8.844l-50.81-87.094V39.688A23.682 23.695 0 0 0 233.154 16h-11.843zM77.75 376A59.994 60 0 0 0 16 436a59.994 60 0 1 0 120 0 59.994 60 0 0 0-58.25-60z" fill="#fff" fill-opacity="1"></path></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

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

After

Width:  |  Height:  |  Size: 1.2 KiB

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

After

Width:  |  Height:  |  Size: 2.1 KiB

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

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

+66
View File
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 433.39499 347.36221"
version="1.1"
id="svg6"
sodipodi:docname="recul.svg"
width="433.39499"
height="347.36221"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1053"
inkscape:window-height="498"
id="namedview8"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="1.4355469"
inkscape:cx="216.6975"
inkscape:cy="201.682"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg6" />
<g
class=""
transform="translate(-39.3025,-82.318)"
id="g4">
<path
d="M 274.663,63.02 90.792,80.26 244.985,99.533 c 5.063,-13.339 12.952,-24.341 22.541,-31.828 a 52.072,52.072 0 0 1 7.137,-4.683 z m 19.832,12.803 c -5.092,0.166 -10.492,2.296 -15.879,6.502 -7.835,6.118 -15.009,16.575 -18.83,29.688 -3.821,13.112 -3.477,26.099 -0.289,35.927 3.188,9.829 8.73,16.071 15.633,18.395 6.903,2.324 14.766,0.596 22.601,-5.522 7.835,-6.117 15.01,-16.574 18.83,-29.687 3.822,-13.113 3.48,-26.1 0.292,-35.928 -3.189,-9.828 -8.73,-16.07 -15.633,-18.394 a 19.017,19.017 0 0 0 -6.725,-0.98 z m 166.85,9.485 c -24.113,13.949 -46.193,20.298 -87.233,17.252 L 340.48,228.452 c -0.675,2.682 -0.318,6 1.922,10.87 2.243,4.876 6.355,10.89 11.836,17.607 9.99,12.242 24.527,27.16 39.573,44.238 14.56,-5.5 28.23,-12.828 38.972,-20.19 11.841,-8.113 20.234,-16.95 21.965,-19.939 l 42.027,-118.22 c -16.748,-14.613 -29.471,-33.974 -35.43,-57.51 z m -288.07,51.261 -149.623,21.762 89.309,12.988 2.158,-5.052 z m 286.265,2.325 16.941,6.078 -39.123,109.037 -37.212,19.181 -8.247,-15.998 30.913,-15.933 z m -259.842,4.394 -70.586,36.043 -29.222,68.422 19.218,8.809 24.905,-57.764 59.299,-22.973 -14.702,75.955 -0.963,1.477 c -32.725,50.18 -71.654,93.41 -118.464,134.28 l -26.461,45.443 17.021,7.245 31.875,-43.989 1.38,-0.906 c 45.476,-29.872 75.93,-62.333 112.255,-94.492 l 4.533,-4.012 5.426,2.686 c 23.365,11.571 42.934,24.117 62.107,37.705 l 8.924,6.324 -69.006,65.643 24.649,39.794 17.67,-10.308 -20.078,-28.477 8.224,-5.004 c 29.884,-18.186 49.986,-39.43 71.938,-66.039 -23.653,-35.6 -42.006,-49.433 -71.592,-71.267 l 9.908,-7.227 c 34.703,-25.312 38.132,-54.476 41.61,-79.449 -9.203,4.441 -19.498,5.772 -29.473,2.414 -13.488,-4.54 -22.924,-16.472 -27.465,-30.473 -0.17,-0.522 -0.321,-1.054 -0.479,-1.584 z m 116.62,45.04 c -1.355,7.027 -3.324,14.17 -6.092,21.349 l 14.056,9.666 5.938,-22.223 z m -174.243,97.476 -126.85,17.953 99.67,14.105 a 598.987,598.987 0 0 0 27.18,-32.058 z m 91.781,82.73 -95.892,21.432 59.406,13.277 z"
fill="#ffffff"
fill-opacity="1"
transform="matrix(0.9,0,0,0.9,25.6,25.6)"
id="path2" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

+110
View File
@@ -0,0 +1,110 @@
<?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 378.00079 384.97681"
version="1.1"
id="svg23"
sodipodi:docname="resistance.svg"
width="378.00079"
height="384.97681"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata27">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1875"
inkscape:window-height="1352"
id="namedview25"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="1.4355469"
inkscape:cx="186.7504"
inkscape:cy="196.1768"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg23" />
<defs
id="defs17">
<linearGradient
x1="0"
x2="1"
y1="1"
y2="0"
id="lorc-aura-gradient-4">
<stop
offset="0%"
stop-color="#4a4a4a"
stop-opacity="1"
id="stop2" />
<stop
offset="100%"
stop-color="#c9c9c9"
stop-opacity="1"
id="stop4" />
</linearGradient>
<radialGradient
id="lorc-aura-gradient-5">
<stop
offset="0%"
stop-color="#9013fe"
stop-opacity="1"
id="stop7" />
<stop
offset="100%"
stop-color="#85562c"
stop-opacity="1"
id="stop9" />
</radialGradient>
<radialGradient
id="lorc-aura-gradient-7">
<stop
offset="0%"
stop-color="#9013fe"
stop-opacity="1"
id="stop12" />
<stop
offset="100%"
stop-color="#85562c"
stop-opacity="1"
id="stop14" />
</radialGradient>
</defs>
<g
class=""
transform="translate(-68.2496,-61.8232)"
id="g21">
<path
d="m 320.938,13.28 c -16.646,34.584 -38.466,60.157 -63.094,60.157 -24.522,0 -47.035,-25.275 -63.656,-59.593 0.366,39.358 -9.71,90.884 -30.938,105.125 -21.228,14.24 -49.64,-12.002 -78.844,-32.126 17.455,34.04 42.095,67.5 29.78,92.28 -12.21,24.576 -59.172,35.96 -92.874,35.626 29.338,19.29 78.842,45.803 78.844,74.188 0.002,28.384 -49.504,53.71 -78.844,73 33.702,-0.333 80.663,11.612 92.876,36.187 12.227,24.61 -9.03,56.31 -33.75,85.563 44.826,-15.413 65.142,-5.735 85.374,10.812 h 31.75 C 154.822,459.086 125.5,386.671 125.5,302.936 125.498,184.316 184.42,88.03 256.906,88.03 c 72.488,0 131.406,96.29 131.406,214.907 0,83.74 -29.317,156.153 -72.062,191.563 h 27.313 c 19.847,-14.62 39.796,-25.65 89.687,-9.28 -26.233,-30.264 -42.2,-62.484 -29.97,-87.095 12.257,-24.665 56.658,-36.612 90.533,-36.188 -29.4,-19.297 -75.344,-44.584 -75.344,-73 0,-28.415 45.943,-54.89 75.342,-74.187 -33.874,0.424 -78.273,-10.962 -90.53,-35.625 -12.315,-24.78 9.982,-58.24 27.437,-92.28 -29.202,20.12 -57.583,46.385 -78.845,32.124 -21.262,-14.263 -31.382,-66.13 -30.938,-105.69 z m -68.97,93.75 c -19.56,2.543 -37.343,25.564 -37.343,55.407 0,16.447 5.67,30.986 14,41.032 l 10.156,12.218 -15.593,2.937 c -10.815,2.035 -18.743,7.737 -25.53,17.063 -6.79,9.325 -11.984,22.344 -15.626,37.343 -6.585,27.128 -8.078,60.24 -8.31,89.47 h 36.093 l 0.656,8.656 9.124,122.563 h 76.187 l 8.095,-122.5 0.563,-8.72 h 34.375 c -0.026,-29.592 -0.44,-63.166 -6.407,-90.5 -3.295,-15.095 -8.287,-28.096 -15.156,-37.313 -6.87,-9.216 -15.133,-14.897 -27.28,-16.78 l -15.94,-2.47 10.064,-12.593 c 7.97,-9.996 13.375,-24.36 13.375,-40.406 -0.002,-31.817 -19.884,-55.313 -41.44,-55.313 -2.54,0 -3.96,-0.103 -4.03,-0.094 h -0.03 z"
fill="#ffffff"
fill-opacity="1"
transform="matrix(0.8,0,0,0.8,51.2,51.2)"
id="path19" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

+163
View File
@@ -1,5 +1,168 @@
# 13.0
## 13.0.20 - L'immobilisme d'Illysis
- Centrage du logo de pause
- Ajout d'un statut malade/empoisonné
- Fenêtre de jet v2
- correction du compteur empoignade
- amélioration des messages liés à l'empoignade
- amélioration des choix de perte d'endurance
- correction de la dépense de rêve sur lancement de sort
- ajustement astrologique sur rituels
## 13.0.19 - L'introspection d'Illysis
- Ajout d'un bouton pour les jets de résistance sous rêve actuel
- Fenêtre de jet v2
- restrictions au propriétaire du personnage
- ouverture de la fenêtre de jets
- appel à la chance
- appel à la destinée
- fermeture par défaut selon le type de jets:
- jets d'attaque
- jets de défense
- jets imposés par un choix d'action
- lancer de sorts
- jets suite à appel à la chance
- gestion des écailles d'efficacité sur les armes
- permettre de faire une attaque même si l'initiative n'est pas faite
- les messages de défense s'affichent correctement avec plusieurs joueurs
- les particulières en force/rapidité sont correctement affichées dans le tchat
- l'expérience sur jet de résistance est limitée à 1 point
## 13.0.18 - Le reflet d'Illysis
- Mise à jour de la feuille de personnage pdf template (avec police correcte)
- Ajout d'une icône "écurie" pour les services des commerces & auberges
- Suppression de message d'erreur sur compétence
manquante à l'ouverture des acteurs d'invocation
## 13.0.17 - Le chant d'Illysis
- Corrections CSS
- Migration Uberwald -> Scriptarium
## 13.0.16 - La paix d'Illysis
- Export de personnages sous forme de feuille de personnage pdf
- Correction d'un problème à l'ouverture de personnages saisis dans d'anciennes versions
- Fenêtre de jet v2
- on peut faire des jets en dehors des combats
## 13.0.15 - Les pièces d'Illysis
- On peut de nouveau acheter dans les commerces
- Corrections V13
- Les textes sur fond "parchemin" ne sont plus affichés en blanc
## 13.0.14 - Le familier d'Illysis
- Les réussites particulières en demi-surprise sont de simples réussites
- Les images des scènes par défaut sont corrigées
- Ajout d'une image de status "sur-encombré"
- Correction V13
- couleur lisible dans les sommaires des journaux et des compendiums
- Amélioration des entités:
- l'attaquant ne sait plus que c'est une entité de cauchemar (surprise!)
- l'encaissement indique une blessure dans le tchat... même si ce n'est que de l'endurance
- les blurettes suivent les règles des entités de cauchemar (p322)
- Nouvelle fenêtre de jets de dés
- attaque/défense des créatures
- les attaques/parades avec une arme trop lourde se font en demi-surprise
- les demandes de défense disparaîssent une fois prises en compte
- empoignade
- l'empoignade est possible avec une initiative d'empoignade, ou en cours d'empoignade
- seule la dague, le pugilat et la dague sont possibles en cours d'empoignade
- jet de Dextérité/Dague pour utiliser la dague en cours d'empoignade (p136)
- attaquer avec une arme un empoigneur donne un +4 si pas d'empoignade (p134)
- la différence de taille donne un bonus/malus en cours d'empoignade (p135)
- les dommages de l'empoignade ajoutent/enlèvent un point d'empoignade
- le statut d'empoignade est affiché sur les tokens
- les défenses contre une empoignade sont corrigées
## 13.0.13 - L'épanouissement d'Illysis
- Fix d'erreur au chargement de templates RollDialog
- Nouvelle fenêtre de jets de dés
- Fix: affichage des points de tâche
- Fix: affichage des ajustements cohérent
- L'ouverture depuis les caractéristiques permet plusieurs types de jets
- On peut créer ou modifier les tâches dans la fenêtre de jets de tâches
- attaque/défense
- les maladresses sont affichées dans le résultat du jet
- le message au défenseur s'affiche correctement
- la difficulté d'attaque s'applique à la défense
- on peut choisir les particulières en rapidité
## 13.0.12 - La méditation d'Illysis
- les signes draconiques éphémères de 1 round sont supprimés à la descente des TMRs
- Générateur de description
- correction des termes pour les couleurs des yeux/cheveux
- ajout de boutons pour forcer le sexe masculin/féminin
- Nouvelle fenêtre de jets de dés
- les méditations proposent un bouton pour monter dans les TMRs
- fenêtre de lancer de sorts
- Correction: les compétences de jeux ne remplacent plus les compétences en dehors des jets de jeu
- gestion des maladresses d'attaque et défense
## 13.0.11 - Le gambit d'Illysis
- Nouvelle fenêtre de jets de dés
- jeux
- cuisine et préparation de nourriture
## 13.0.10 - Les papilles d'Illysis
- Ajout d'un statut "saignement" en cas de blessure grave ou critique sans premiers soins
- Nouvelle fenêtre de jets de dés
- jets de méditation
- jets de tâches
- jets de caractéristiques
- jets de compétences
- Boutons d'initiative et d'attaque V2
- fenêtre d'attaque
- choix des armes
- gestion des particulières
- message au défenseur
- gestion des demi-surprises (attaquant/défenseur)
- gestion des tactiques (attaquant/défenseur)
- en cours nouvelle fenêtre de jets
- jets de compétence avec messages
- jets de cuisine séparés avec messages (pour gérer plus tard les spécificités: fabricatioon de plats)
- gestion des empoignades
- Technique: suppression de warnings foundry sur renderTemplate
## 13.0.9 - Le combat d'Illysis
- Fix
- La montée en TMR fonctionne
- ajout d'un status "Force insuffisante"
- clarification des maladresses à l'attaque (en demi surprise, ou à cause d'un échec total)
- Nouvelle fenêtre de jets de dés
- ajout du statut "Force insuffisante" aux acteurs si la
force est insuffisante pour l'arme
- avancement du mode attaque
- choix de tactique
- choix mortel/non-mortel pour les dommages
- affichage des dommages ajustés delon les choix
- affichage du statut de surprise de l'attaquant
- affichage du statut de surprise du défenseur
- prise en compte des significatives (demi-surprises)
- avancement du mode défense
- sélection esquive/parade
- affichage du statut de surprise du défenseur
- prise en compte des significatives (demi-surprises, armes disparates,
particulière en finesse)
- gestion de l'appel à la chance
- gestion de l'utilisation de la destinée
- gestion du recul depuis le messages
- gestion de l'encaissement depuis le messages
- impossible de faire un jet "actif" en surprise totale (attaque, parade, ...)
## 13.0.8 - Le renouveau d'Illysis
- Fix Foundry V13
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.3 KiB

+6 -3
View File
@@ -1,6 +1,6 @@
{
"TYPES": {
"Actor": {
"Actor": {
"personnage": "Personnage",
"creature": "Créature",
"entite": "Entité de cauchemar",
@@ -63,9 +63,12 @@
"StatusUnarmed": "Désarmé",
"StatusGrappling": "Empoignade",
"StatusGrappled": "Empoigné",
"StatusMalade": "Malade",
"StatusRestrained": "Immobilisé",
"StatusComma": "Comma",
"StatusDead": "Mort",
"StatusDemiReve": "Demi-rêve"
"StatusDemiReve": "Demi-rêve",
"StatusSurEnc": "Sur-encombrement",
"StatusForceWeak": "Force insuffisante"
}
}
}
+8 -1
View File
@@ -27,6 +27,11 @@
--gradient-red: linear-gradient(150deg, rgba(255, 0, 0, 0.3), rgba(255, 200, 128, 0.05),rgba(255, 200, 128, 0.1), rgba(255,10,0,0.3));
--gradient-violet: linear-gradient(150deg, rgba(100, 45, 124, 0.6), rgba(216, 157, 192, 0.3), rgba(177, 157, 216, 0.5), rgba(107, 62, 121, 0.3), rgba(100, 45, 124, 0.6));
--gradient-purple-black: linear-gradient(150deg, rgba(0, 0, 0, 0.7), rgba(100, 45, 124, 0.4), rgba(82, 17, 131, 0.3),rgba(100, 45, 124, 0.4), rgba(0, 0, 0, 0.7));
--gradient-warning: linear-gradient(150deg,
hsla(32, 100%, 50%, 0.3),
hsla(52, 60%, 50%, 0.1),
hsla(32, 60%, 50%, 0.1),
hsla(32, 100%, 50%, 0.3));
--gradient-silver-light: linear-gradient(30deg, rgba(61, 55, 93, 0.2), rgba(178, 179, 196, 0.1), rgba(59, 62, 63, 0.2), rgba(206, 204, 199, 0.1), rgba(61, 46, 49, 0.2));
--gradient-daylight: conic-gradient(
from 0deg,
@@ -39,7 +44,9 @@
hsla(50, 100%, 80%, 0.7)
);
--background-custom-button: linear-gradient(to bottom, hsla(208, 38%, 21%, 0.988) 5%, hsla(202, 42%, 14%, 0.671) 100%);
--background-color-button: hsl(25, 5%, 60%);
--background-color-custom-button: hsla(208, 38%, 21%, 0.988);
--background-custom-button: linear-gradient(to bottom, var(--background-color-custom-button) 5%, hsla(202, 42%, 14%, 0.671) 100%);
--background-custom-button-hover: linear-gradient(to bottom, hsla(0, 100%, 25%, 1) 5%, hsla(0, 97%, 12%, 1) 100%);
--background-control-selected: linear-gradient(to bottom, hsla(0, 100%, 25%, 0.5) 5%, hsla(0, 100%, 12%, 0.5) 100%);
--background-tooltip: hsla(60, 12%, 85%, 0.95);
+2 -3
View File
@@ -70,8 +70,7 @@
/* Fonts */
.sheet header.sheet-header h1 input,
.window-app .window-header,
#actors .directory-list,
#navigation #scene-list .scene.nav-item {
#sidebar {
font-family: "GoudyAcc"
}
@@ -80,6 +79,6 @@
.window-app input,
.sheet header.sheet-header .header-compteurs,
.sheet header.sheet-header .flex-group-center.flex-fatigue,
select, .item-checkbox, #sidebar, #players, #navigation #nav-toggle {
select, .item-checkbox, #players {
font-family: "CaslonAntique"; /* For sheet parts; For nav and title */
}
File diff suppressed because it is too large Load Diff
+89
View File
@@ -0,0 +1,89 @@
.chat-message div.roll-chat,
.dialog-content div.roll-chat {
font-family: CaslonAntique;
display: grid;
grid-template-areas:
"img header buttons"
"img resume buttons"
"details details details"
"actions actions actions";
grid-template-columns: 3rem 1fr 1.4rem;
grid-template-rows: max-content max-content max-content max-content;
gap: 0 0.5rem;
div.chat-img {
grid-area: img;
display: flex;
flex-direction: column;
img {
border: 0;
max-height: 3rem;
max-width: 3rem;
object-fit: contain;
height: 100%;
}
}
div.chat-header {
grid-area: header;
font-weight: bold;
font-size: 0.9rem;
}
div.chat-resume {
grid-area: resume;
text-align: justify;
}
div.chat-details {
grid-area: details;
text-align: justify;
display: flex;
flex-direction: column;
div {
display: block;
}
}
div.chat-actions {
grid-area: actions;
display: flex;
flex-direction: column;
a {
display: flex;
flex-direction: row;
img {
margin-right: 0.5rem;
}
}
}
div.chat-buttons {
grid-area: buttons;
display: flex;
flex-direction: column;
a {
border-radius: 0.2rem;
cursor: pointer;
padding: 0.2rem;
position: relative;
box-shadow: inset 1x 1px #a6827e;
color: var(--color-controls);
border: 1px ridge #846109;
display: inline-block;
align-items: center;
img {
max-width: 1rem;
max-height: 1rem;
}
}
a:hover {
background: var(--background-custom-button-hover);
}
a:active{
position:relative;
top:1px;
}
}
}
+64 -21
View File
@@ -4,11 +4,11 @@
grid-template-areas:
"header header header header header header header"
"action action action action action action action"
"mode separation separation separation separation separation separation"
"mode carac carac carac comp comp resume"
"mode choix choix choix choix choix modifiers"
"mode resolution resolution resolution resolution resolution modifiers"
"mode chances chances chances chances chances buttons"
"type separation separation separation separation separation separation"
"type carac carac carac comp comp resume"
"type choix choix choix choix choix conditions"
"type resolution resolution resolution resolution resolution conditions"
"type chances chances chances chances chances buttons"
"footer footer footer footer footer footer footer";
grid-template-columns: 2rem 1rem 1fr 1fr 2fr 2fr 3fr;
gap: 0.2rem;
@@ -22,18 +22,18 @@
roll-choix { grid-area: choix; }
roll-table { grid-area: resolution; }
roll-conditions { grid-area: modifiers; }
roll-conditions { grid-area: conditions; }
roll-chances { grid-area: chances; }
roll-resume { grid-area: resume; }
roll-buttons { grid-area: buttons; }
roll-mode {
grid-area: mode;
roll-type {
grid-area: type;
display: flex;
flex-direction: column;
}
roll-conditions roll-section[name="rollmode"],
roll-mode {
roll-type {
button[data-checked="true"] {
background-color: var(--color-text-selection-bg);
color: var(--color-controls);
@@ -83,16 +83,23 @@
gap: 0.2rem;
align-items: start;
subline {
grid-area: selection;
display: flex;
flex-direction: row;
margin: 0.1rem 0;
.warning {
border-radius: 0.5rem;
background: var(--gradient-warning);
}
}
roll-part-img {
display: flex;
flex-direction: column;
grid-area: img;
img{
img {
border: 0;
padding: 1px;
max-height: 3rem;
@@ -110,9 +117,22 @@
subline {
display: flex;
flex-direction: row;
margin: 0.1rem 0;
div.poesie-extrait{
display: flex;
flex-direction: column;
align-items: normal;
}
span.status-surprise{
display: flex;
flex-direction: row;
flex-flow: wrap;
img {
filter: invert(0.8);
}
}
label {
align-content: center;
}
}
}
@@ -122,8 +142,13 @@
display: flow;
width: 2.5rem;
text-align: right;
margin: 0 0.2rem 0 0.5rem;
margin: 0 0.2rem;
padding: 0 0.2rem;
border: 1px solid ;
border-radius: 0.2rem ;
background: hsla(0, 0%, 0%, 0.2);
height: 1.5rem;
background: hsla(0, 0%, 0%, 0.2);
}
roll-action {
@@ -135,6 +160,9 @@
font-size: 1.2rem;
font-weight: bold;
roll-section[name="resistance"] {
align-items: flex-end;
}
roll-section {
display: flex;
flex-direction: row;
@@ -149,6 +177,12 @@
margin: 0 1rem;
padding: 0;
}
img.flag-resistance {
max-width: 1.5rem;
max-height: 1.5rem;
text-align: right;
filter: invert(0.6);
}
}
}
@@ -178,31 +212,40 @@
margin: 0 0.2rem;
padding: 0;
}
img.button-effect-img {
max-width: 1rem;
max-height: 1rem;
margin: 0 0.1rem;
}
}
roll-carac select[name="select-carac"] {
max-width: 6rem;
}
min-width: 6.5rem;
max-width: 8rem;
}
roll-comp select[name="select-comp"] {
min-width: 8rem;
max-width: 11rem;
margin-left: 1rem;
}
max-width: 10rem;
margin-left: 1.5rem;
}
roll-conditions roll-section[name="coeur"] select[name="coeur"] {
max-width: 4rem;
}
roll-conditions roll-section[name="tricher"] img {
/* image de d100 */
max-width: 2.5rem;
max-height: 2.5rem;
roll-conditions roll-section img {
max-width: 1rem;
max-height: 1rem;
gap: 0;
margin: 0;
padding: 0;
filter: invert(0.8);
}
roll-conditions roll-section[name="tricher"] img {
/* image de d100 */
max-width: 2.5rem;
max-height: 2.5rem;
}
roll-buttons {
display: flex;
+3 -3
View File
@@ -8,7 +8,7 @@
min-height: 100px; // Hauteur minimale pour la description
background: var(--rdd-bg-input-alt); // Une couleur de fond alternative
padding: 5px;
border-radius: 3px;
border-radius: 0.2rem;
color: var(--rdd-color-text-primary);
}
@@ -28,7 +28,7 @@
background: var(--fieldset-background);
color: var(--rdd-color-text-primary);
margin-bottom: 4px;
border-radius: 6px;
border-radius: 0.5rem;
border-color: var(--rdd-color-text-primary);
border-width: 2px;
}
@@ -64,7 +64,7 @@
--rdd-color-text-input
); // Assurez-vous que cette variable existe
padding: 2px 2px; // Augmentation du padding vertical
border-radius: 3px;
border-radius: 0.2rem;
}
input[type="checkbox"] {
+1 -1
View File
@@ -1,4 +1,4 @@
import { SYSTEM_RDD } from "../constants.js";
import { renderTemplate, SYSTEM_RDD } from "../constants.js";
import { RdDUtility } from "../rdd-utility.js";
const DETAIL_VENTE = 'detailVente';
+1
View File
@@ -1,3 +1,4 @@
import { renderTemplate } from "../constants.js";
import { Misc } from "../misc.js";
import { RdDUtility } from "../rdd-utility.js";
import { ChatVente } from "./chat-vente.js";
+1
View File
@@ -1,3 +1,4 @@
import { renderTemplate } from "../constants.js";
import { HtmlUtility } from "../html-utility.js";
import { RdDUtility } from "../rdd-utility.js";
import { ChatVente } from "./chat-vente.js";
+6 -14
View File
@@ -3,7 +3,7 @@ import { HtmlUtility } from "./html-utility.js";
import { RdDBonus } from "./rdd-bonus.js";
import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js";
import { RdDCarac } from "./rdd-carac.js";
import { CARACS, RdDCarac } from "./rdd-carac.js";
import { DialogSplitItem } from "./dialog-split-item.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
@@ -11,7 +11,6 @@ import { MAINS_DIRECTRICES } from "./actor.js";
import { RdDBaseActorReveSheet } from "./actor/base-actor-reve-sheet.js";
import { ITEM_TYPES } from "./constants.js";
import { RdDItem } from "./item.js";
import { RdDItemArme } from "./item/arme.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemBlessure } from "./item/blessure.js";
import { RdDEmpoignade } from "./rdd-empoignade.js";
@@ -49,7 +48,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
});
foundry.utils.mergeObject(formData.calc, {
surenc: this.actor.computeMalusSurEncombrement(),
surprise: RdDBonus.find(this.actor.getSurprise(false)).descr,
surprise: RdDBonus.find(this.actor.getSurprise(false)).label,
resumeBlessures: this.actor.computeResumeBlessure(this.actor.system.blessures),
caracTotal: RdDCarac.computeTotal(this.actor.system.carac, this.actor.system.beaute),
surEncombrementMessage: this.actor.isSurenc() ? "Sur-Encombrement!" : "",
@@ -175,7 +174,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
await this.getBlessure(event)?.setSoinsBlessure({ soinscomplets: { bonus: Number(event.currentTarget.value) } })
});
this.html.find('.roll-chance-actuelle').click(async event => await this.actor.rollCarac('chance-actuelle'))
this.html.find('.roll-chance-actuelle').click(async event => await this.actor.rollCarac(CARACS.CHANCE_ACTUELLE))
this.html.find('.button-appel-chance').click(async event => await this.actor.rollAppelChance())
this.html.find('[name="jet-astrologie"]').click(async event => await this.actor.astrologieNombresAstraux())
@@ -209,7 +208,8 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
}
// Points de reve actuel
this.html.find('.roll-reve-actuel').click(async event => await this.actor.rollCarac('reve-actuel', { resistance: true }))
this.html.find('.roll-reve-actuel').click(async event => await this.actor.rollReveActuel({ resistance: false }))
this.html.find('.button-reve-resistance').click(async event => await this.actor.rollReveActuel({ diff: -8, resistance: true }))
this.html.find('.action-empoignade').click(async event => await RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor)))
this.html.find('.roll-arme').click(async event => {
@@ -343,7 +343,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
/* -------------------------------------------- */
async createEmptyTache() {
await this.actor.createItem('tache', 'Nouvelle tache');
await this.actor.createItem(ITEM_TYPES.tache, 'Nouvelle tache')
}
_getActionCombat(event) {
@@ -376,14 +376,6 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
return position;
}
/* -------------------------------------------- */
/** @override */
_updateObject(event, formData) {
// Update the Actor
return this.actor.update(formData);
}
async splitItem(item) {
const dialog = await DialogSplitItem.create(item, (item, split) => this._onSplitItem(item, split));
dialog.render(true);
+269 -191
View File
@@ -14,12 +14,12 @@ import { STATUSES } from "./settings/status-effects.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
import { Draconique } from "./tmr/draconique.js";
import { LIST_CARAC_PERSONNAGE, RdDCarac } from "./rdd-carac.js";
import { CARACS, LIST_CARAC_PERSONNAGE, RdDCarac } from "./rdd-carac.js";
import { DialogConsommer } from "./dialog-item-consommer.js";
import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js";
import { RollDataAjustements } from "./rolldata-ajustements.js";
import { RollDataAjustements } from "./rolldata-ajustements-v1.js";
import { RdDPossession } from "./rdd-possession.js";
import { ACTOR_TYPES, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { ACTOR_TYPES, renderTemplate, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { RdDConfirm } from "./rdd-confirm.js";
import { DialogRepos } from "./sommeil/dialog-repos.js";
import { RdDBaseActor } from "./actor/base-actor.js";
@@ -31,9 +31,8 @@ import { ITEM_TYPES } from "./constants.js";
import { RdDBaseActorSang } from "./actor/base-actor-sang.js";
import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { DialogChoixXpCarac } from "./dialog-choix-xp-carac.js";
import { RdDCombatManager } from "./rdd-combat.js";
import { RdDItemArme } from "./item/arme.js";
import { ATTAQUE_TYPE, RdDItemArme } from "./item/arme.js";
import { RdDItemBlessure } from "./item/blessure.js";
import { RdDItemTete } from "./item/tete.js";
import { RdDItemSort } from "./item-sort.js";
@@ -47,7 +46,12 @@ import { PAS_DE_DRACONIC, POSSESSION_SANS_DRACONIC } from "./item/base-items.js"
import { RdDRollResult } from "./rdd-roll-result.js";
import { RdDInitiative } from "./initiative.mjs";
import RollDialog from "./roll/roll-dialog.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js";
import { OptionsAvancees, ROLL_DIALOG_V2, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js";
import { ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_SORT } from "./roll/roll-constants.mjs";
import { PART_TACHE } from "./roll/roll-part-tache.mjs";
import { PART_COMP } from "./roll/roll-part-comp.mjs";
import { PART_OEUVRE } from "./roll/roll-part-oeuvre.mjs";
import { PART_CUISINE } from "./roll/roll-part-cuisine.mjs";
export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre']
@@ -99,6 +103,8 @@ export class RdDActor extends RdDBaseActorSang {
}
isPersonnage() { return true }
isFeminin() { return this.system.sexe.length > 0 && this.system.sexe.charAt(0).toLowerCase() == 'f' }
isHautRevant() { return this.system.attributs.hautrevant.value != "" }
/* -------------------------------------------- */
@@ -124,11 +130,6 @@ export class RdDActor extends RdDBaseActorSang {
return etatGeneral
}
/* -------------------------------------------- */
getActivePoisons() {
return foundry.utils.duplicate(this.items.filter(item => item.type == 'poison' && item.system.active))
}
/* -------------------------------------------- */
getMalusArmure() {
return this.itemTypes[ITEM_TYPES.armure].filter(it => it.system.equipe)
@@ -137,12 +138,12 @@ export class RdDActor extends RdDBaseActorSang {
}
listActions({ isAttaque = false, isEquipe = false }) {
// Recupération des armes
// Recupération des attaques
const actions = this.listActionsAttaque()
.filter(it => !isEquipe || it.arme.system.equipe)
if (!isAttaque && this.system.attributs.hautrevant.value) {
actions.push({ name: "Draconic", action: 'haut-reve', initOnly: true })
actions.push({ label: "Draconic", action: 'haut-reve', initOnly: true })
}
return actions
}
@@ -159,71 +160,71 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
getDemiReve() { return this.system.reve.tmrpos.coord }
getDraconicList() { return this.itemTypes[ITEM_TYPES.competence].filter(it => it.system.categorie == 'draconic') }
getBestDraconic() { return foundry.utils.duplicate([...this.getDraconicList(), PAS_DE_DRACONIC].sort(Misc.descending(it => it.system.niveau)).find(it => true)) }
getDraconics() { return this.itemTypes[ITEM_TYPES.competence].filter(it => it.system.categorie == 'draconic') }
getBestDraconic() { return foundry.utils.duplicate([...this.getDraconics(), PAS_DE_DRACONIC].sort(Misc.descending(it => it.system.niveau)).find(it => true)) }
getDraconicOuPossession() {
return [...this.getDraconicList().filter(it => it.system.niveau >= 0), POSSESSION_SANS_DRACONIC]
return [...this.getDraconics().filter(it => it.system.niveau >= 0), POSSESSION_SANS_DRACONIC]
.sort(Misc.descending(it => it.system.niveau))
.find(it => true)
}
isForceInsuffisante(forceRequise) {
const force = parseInt(this.system.carac.force.value)
return forceRequise > force
}
/* -------------------------------------------- */
/** Retourne une liste triée d'actions d'armes avec le split arme1 main / arme 2 main / lancer */
listActionsAttaque() {
let actions = [
this.$prepareAttaqueArme(RdDItemArme.empoignade(this)),
this.$prepareAttaqueArme(RdDItemArme.corpsACorps(this)),
]
const actions = []
const uniques = []
const armes = this.itemTypes[ITEM_TYPES.arme]
.filter(it => RdDItemArme.isAttaque(it))
.sort(Misc.ascending(it => it.name));
const addAttaque = (arme, main = undefined) => {
const dommages = RdDItemArme.valeurMain(arme.system.dommages, main)
const forceRequise = RdDItemArme.valeurMain(arme.system.force ?? 0, main)
const ecaillesEfficacite = arme.system.magique ? arme.system.ecaille_efficacite : 0;
for (const arme of armes) {
if (arme.system.unemain && arme.system.competence) {
actions.push(this.$prepareAttaqueArme(arme, '(1 main)'))
const comp = this.getCompetence(arme.getCompetenceAction(main), { onMessage: message => { console.info(message) } })
if (!comp) {
return
}
if (arme.system.deuxmains && arme.system.competence) {
actions.push(this.$prepareAttaqueArme(arme, '(2 mains)'))
}
if (arme.system.lancer) {
actions.push(this.$prepareAttaqueArme(arme, '(lancer)'))
}
if (arme.system.tir) {
actions.push(this.$prepareAttaqueArme(arme, '(tir)'))
const unique = [comp.id, arme.name, dommages, forceRequise, ecaillesEfficacite].join('|');
if (uniques.includes(unique)) {
return
}
uniques.push(unique);
const caracCode = RdDActor.$getCaracAction(comp, main)
const caracValue = this.system.carac[caracCode].value
const niveau = comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(main) ? -8 : -6)
const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + ecaillesEfficacite
actions.push({
label: arme.name + (main ? ' ' + main : ''),
action: 'attaque',
initOnly: false,
arme: arme,
comp: comp,
main: main,
carac: { key: caracCode, value: caracValue },
equipe: arme.system.equipe,
dommages: dommages,
forceRequise: forceRequise,
initiative: RdDInitiative.getRollInitiative(caracValue, niveau, ajustement)
})
}
return actions;
}
/* -------------------------------------------- */
$prepareAttaqueArme(arme, main) {
const comp = this.getCompetence(RdDActor.$getCompetenceAction(arme, main))
const caracCode = RdDActor.$getCaracAction(comp, main)
const caracValue = this.system.carac[caracCode].value
const dommages = arme.system.dommages.toString()
addAttaque(RdDItemArme.empoignade(this), ATTAQUE_TYPE.CORPS_A_CORPS)
// TODO: déplacer sur RdDItemArme
if (arme.system.unemain && arme.system.deuxmains && !dommages.includes("/")) {
ui.notifications.info(`Les dommages de l'arme à 1/2 mains ${arme.name} ne sont pas corrects (ie sous la forme X/Y)`)
}
const tableauDommages = dommages.includes("/") ? dommages.split("/") : [dommages, dommages]
const dmg = main == '(2 mains)' ? tableauDommages[1] : tableauDommages[0]
const niveau = comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(main) ? -8 : -6)
const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + (arme.system.magique) ? arme.system.ecaille_efficacite : 0
this.itemTypes[ITEM_TYPES.arme]
.filter(it => it.isAttaque())
.sort(Misc.ascending(it => it.name))
.forEach(arme => arme.getTypeAttaques().forEach(t => addAttaque(arme, t)))
return {
name: arme.name + (main ? ' ' + main : ''),
action: 'attaque',
initOnly: false,
arme: arme,
comp: comp,
main: main,
carac: { key: caracCode, value: caracValue },
equipe: arme.system.equipe,
dmg: dmg,
initiative: RdDInitiative.calculInitiative(niveau, caracValue, ajustement)
}
addAttaque(RdDItemArme.pugilat(this), ATTAQUE_TYPE.CORPS_A_CORPS)
return actions
}
static $getCaracAction(comp, main) {
@@ -237,16 +238,6 @@ export class RdDActor extends RdDBaseActorSang {
}
}
static $getCompetenceAction(arme, main) {
switch (main) {
case '(1 main)': return arme.competence1Mains()
case '(2 mains)': return arme.competence2Mains()
case '(lancer)': return arme.system.lancer
case '(tir)': return arme.system.tir
default: return arme.system.competence
}
}
/* -------------------------------------------- */
async $perteReveEnchantementsChateauDormants() {
const toUpdate = this.items.filter(it => [ITEM_TYPES.potion, ITEM_TYPES.gemme].includes(it.type))
@@ -336,10 +327,6 @@ export class RdDActor extends RdDBaseActorSang {
await this._recupererVie(message, isMaladeEmpoisonne);
}
getMaladiesPoisons() {
return this.items.filter(item => item.type == 'maladie' || (item.type == 'poison' && item.system.active));
}
_messageRecuperationMaladiePoisons(maladiesPoisons, message) {
if (maladiesPoisons.length > 0) {
const identifies = maladiesPoisons.filter(it => it.system.identifie);
@@ -507,7 +494,7 @@ export class RdDActor extends RdDBaseActorSang {
'system.sante.fatigue.value': 0,
'system.compteurs.ethylisme': { value: 1, nb_doses: 0, jet_moral: false }
})
await this.removeEffects(e => e.id != STATUSES.StatusDemiReve);
await this.removeEffects(e => !e.statuses?.has(STATUSES.StatusDemiReve));
await this.supprimerBlessures(it => true);
await ChatMessage.create({
whisper: ChatUtility.getOwners(this),
@@ -698,11 +685,12 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async combattreReveDeDragon(force) {
const rencontre = await game.system.rdd.rencontresTMR.getReveDeDragon(force);
let rollData = {
actor: this,
competence: this.getDraconicOuPossession(),
canClose: false,
rencontre: await game.system.rdd.rencontresTMR.getReveDeDragon(force),
rencontre: rencontre,
tmr: true,
use: { libre: false, conditions: false },
forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: this.getReveActuel() } }
@@ -733,12 +721,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async sortMisEnReserve(sort, draconic, coord, ptreve) {
await this.createEmbeddedDocuments("Item", [{
type: ITEM_TYPES.sortreserve,
name: sort.name,
img: sort.img,
system: { sortid: sort._id, draconic: (draconic?.name ?? sort.system.draconic), ptreve: ptreve, coord: coord, heurecible: 'Vaisseau' }
}],
await this.createEmbeddedDocuments("Item", [RdDItemSort.prepareSortEnReserve(sort, draconic, ptreve, coord)],
{ renderSheet: false });
this.tmrApp.updateTokens();
}
@@ -752,20 +735,18 @@ export class RdDActor extends RdDBaseActorSang {
let updates = {};
if (caracName == LIST_CARAC_PERSONNAGE.reve.code) {
if (to > Misc.toInt(this.system.reve.seuil.value)) {
updates[`system.reve.seuil.value`] = to; // SFA : Direct and packed changes
//this.setPointsDeSeuil(to);
updates[`system.reve.seuil.value`] = to
}
}
if (caracName == LIST_CARAC_PERSONNAGE.chance.code) {
if (to > Misc.toInt(this.system.compteurs.chance.value)) {
updates[`system.compteurs.chance.value`] = to; // SFA : Direct and packed changes
//this.setPointsDeChance(to);
updates[`system.compteurs.chance.value`] = to
}
}
let selectedCarac = this.findCaracByName(caracName);
const from = selectedCarac.value
updates[`system.carac.${caracName}.value`] = to;
await this.update(updates);
await this.update(updates, { noHook: true });
await ExperienceLog.add(this, XP_TOPIC.CARAC, from, to, caracName);
}
@@ -1343,7 +1324,7 @@ export class RdDActor extends RdDBaseActorSang {
async _apprecierCuisine(item, seForcer) {
const surmonteExotisme = await this._surmonterExotisme(item, seForcer);
if (surmonteExotisme) {
await this.apprecier('gout', 'cuisine', item.system.qualite, item.system.boisson ? "apprécie la boisson" : "apprécie le plat");
await this.apprecier(CARACS.ODORATGOUT, 'cuisine', item.system.qualite, item.system.boisson ? "apprécie la boisson" : "apprécie le plat");
}
else if (seForcer) {
await this.jetDeMoral('malheureux');
@@ -1361,7 +1342,7 @@ export class RdDActor extends RdDBaseActorSang {
if (exotisme < 0 || qualite < 0) {
const competence = qualite > 0 ? 'cuisine' : undefined
const difficulte = Math.min(exotisme, qualite)
const rolled = await this.doRollCaracCompetence('volonte', competence, difficulte, { title: `tente de surmonter l'exotisme de ${item.name}` })
const rolled = await this.doRollCaracCompetence(CARACS.VOLONTE, competence, difficulte, { title: `tente de surmonter l'exotisme de ${item.name}` })
return rolled.isSuccess
}
return true;
@@ -1646,7 +1627,8 @@ export class RdDActor extends RdDBaseActorSang {
return
}
hideChatMessage = hideChatMessage == 'hide' || (Misc.isRollModeHiddenToPlayer() && !game.user.isGM)
let xpData = await this._appliquerExperience(rollData.rolled, rollData.selectedCarac.label, rollData.competence, rollData.jetResistance);
let xpData = await this._appliquerExperience(rollData.rolled, rollData.selectedCarac.label, rollData.competence,
rollData.v2 ? rollData.type.resistance : rollData.jetResistance);
if (xpData.length) {
const content = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-gain-xp.hbs`, {
actor: this,
@@ -1683,7 +1665,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
computeDraconicAndSortIndex(sortList) {
let draconicList = this.getDraconicList();
let draconicList = this.getDraconics();
for (let sort of sortList) {
let draconicsSort = RdDItemSort.getDraconicsSort(draconicList, sort).map(it => it.name);
for (let index = 0; index < draconicList.length && sort.system.listIndex == undefined; index++) {
@@ -1704,15 +1686,18 @@ export class RdDActor extends RdDBaseActorSang {
ui.notifications.error("Une queue ou un souffle vous empèche de lancer de sort!")
return
}
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
return await this.rollUnSortV2();
}
// Duplication car les pts de reve sont modifiés dans le sort!
let sorts = foundry.utils.duplicate(this.itemTypes[ITEM_TYPES.sort].filter(it => RdDItemSort.isSortOnCoord(it, coord)))
if (sorts.length == 0) {
ui.notifications.info(`Aucun sort disponible en ${TMRUtility.getTMR(coord).label} !`);
return;
return
}
const draconicList = this.computeDraconicAndSortIndex(sorts);
const reve = foundry.utils.duplicate(this.system.carac.reve);
const draconicList = this.computeDraconicAndSortIndex(sorts)
const reve = foundry.utils.duplicate(this.system.carac.reve)
const dialog = await this.openRollDialog({
name: 'lancer-un-sort',
@@ -1735,6 +1720,27 @@ export class RdDActor extends RdDBaseActorSang {
this.tmrApp?.setTMRPendingAction(dialog);
}
async rollUnSortV2() {
const rollData = {
ids: { actorId: this.id },
type: { allowed: [ROLL_TYPE_SORT], current: ROLL_TYPE_SORT }
};
const dialog = await RollDialog.create(rollData, {
callbacks: [async roll => {
await this.tmrApp?.restoreTMRAfterAction();
if (roll.closeTMR) {
await this.tmrApp?.close();
this.tmrApp = undefined;
}
}],
onRollDone: RollDialog.onRollDoneClose,
onClose: async () => {
await this.tmrApp?.restoreTMRAfterAction();
}
});
this.tmrApp?.setTMRPendingAction(dialog);
}
/* -------------------------------------------- */
isMauvaiseRencontre() { // Gestion queue/souffle 'Mauvaise Rencontre en Perpective'
let addMsg = "";
@@ -1806,11 +1812,7 @@ export class RdDActor extends RdDBaseActorSang {
}
else {
console.log('lancement de sort', rollData.selectedSort)
const precedents = rollData.selectedSort.system.lancements ?? []
const lancements = [...precedents, {
timestamp: game.system.rdd.calendrier.getTimestamp(),
reve: rollData.selectedSort.system.ptreve_reel
}]
const lancements = RdDItemSort.prepareSortAddLancement(rollData.selectedSort, rollData.selectedSort.system.ptreve_reel)
await this.updateEmbeddedDocuments('Item',
[{ _id: rollData.selectedSort._id, 'system.lancements': lancements }]
)
@@ -1923,6 +1925,20 @@ export class RdDActor extends RdDBaseActorSang {
}
async rollCaracCompetence(caracName, compName, diff, options = { title: "" }) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: { allowed: [PART_COMP], current: PART_COMP },
selected: {
carac: { key: caracName },
comp: { key: compName, forced: options.forced },
diff: { value: diff ?? 0 }
}
}
return await RollDialog.create(rollData)
}
RdDEmpoignade.checkEmpoignadeEnCours(this)
const competence = this.getCompetence(compName);
await this.openRollDialog({
@@ -1945,23 +1961,33 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async rollTache(id, options = {}) {
RdDEmpoignade.checkEmpoignadeEnCours(this)
const tacheData = this.getTache(id)
const compData = this.getCompetence(tacheData.system.competence)
compData.system.defaut_carac = tacheData.system.carac; // Patch !
const tache = this.getTache(id)
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
selected: { tache: { key: tache.id, forced: options.forced } },
type: { allowed: [PART_TACHE], current: PART_TACHE }
}
return await RollDialog.create(rollData)
}
const compData = this.getCompetence(tache.system.competence)
compData.system.defaut_carac = tache.system.carac; // Patch !
await this.openRollDialog({
name: 'jet-competence',
label: 'Jet de Tâche ' + tacheData.name,
label: 'Jet de Tâche ' + tache.name,
template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.hbs',
rollData: {
competence: compData,
tache: tacheData,
diffLibre: tacheData.system.difficulte,
tache: tache,
diffLibre: tache.system.difficulte,
diffConditions: 0,
use: { libre: false, conditions: true },
carac: {
[tacheData.system.carac]: foundry.utils.duplicate(this.system.carac[tacheData.system.carac])
[tache.system.carac]: foundry.utils.duplicate(this.system.carac[tache.system.carac])
}
},
callbacks: [{ action: r => this._tacheResult(r, options) }]
@@ -1995,9 +2021,18 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async rollJeu(id) {
const oeuvre = this.getJeu(id);
const jeu = this.getJeu(id);
const listCarac = oeuvre.system.caraccomp.toLowerCase().split(/[.,:\/-]/).map(it => it.trim());
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
selected: { jeu: { key: jeu.id } },
type: { allowed: [ROLL_TYPE_JEU], current: ROLL_TYPE_JEU }
}
return await RollDialog.create(rollData)
}
const listCarac = jeu.system.caraccomp.toLowerCase().split(/[.,:\/-]/).map(it => it.trim());
const carac = listCarac.length > 0 ? listCarac[0] : 'chance'
const artData = {
art: 'jeu', verbe: 'Jeu',
@@ -2007,14 +2042,24 @@ export class RdDActor extends RdDBaseActorSang {
};
listCarac.forEach(c => artData.forceCarac[c] = this.system.carac[c]);
artData.competence.system.niveauReel = artData.competence.system.niveau;
artData.competence.system.niveau = Math.max(artData.competence.system.niveau, oeuvre.system.base);
await this._rollArtV1(artData, carac, oeuvre);
artData.competence.system.niveau = Math.max(artData.competence.system.niveau, jeu.system.base);
await this._rollArtV1(artData, carac, jeu);
}
/* -------------------------------------------- */
async rollMeditation(id) {
const meditation = foundry.utils.duplicate(this.getMeditation(id));
if (meditation && OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
selected: { meditation: { key: id } },
type: { allowed: [ROLL_TYPE_MEDITATION], current: ROLL_TYPE_MEDITATION }
}
return await RollDialog.create(rollData)
}
const competence = foundry.utils.duplicate(this.getCompetence(meditation.system.competence));
competence.system.defaut_carac = "intellect"; // Meditation = toujours avec intellect
let meditationData = {
@@ -2054,7 +2099,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
_getSignesDraconiques(coord) {
const type = TMRUtility.getTMRType(coord);
return this.itemTypes["signedraconique"].filter(it => it.system.typesTMR.includes(type));
return this.itemTypes[ITEM_TYPES.signedraconique].filter(it => it.system.typesTMR.includes(type));
}
/* -------------------------------------------- */
@@ -2066,18 +2111,19 @@ export class RdDActor extends RdDBaseActorSang {
async rollLireSigneDraconique(coord) {
if (!this.isHautRevant()) {
ui.notifications.info("Seul un haut rêvant peut lire un signe draconique!");
return;
return
}
let signes = this._getSignesDraconiques(coord);
let signes = this._getSignesDraconiques(coord)
if (signes.length == 0) {
ui.notifications.info(`Aucun signe draconiques en ${coord} !`);
return;
ui.notifications.info(`Aucun signe draconiques en ${coord} !`)
return
}
let draconicList = this.getDraconicList()
let draconicList = this.getDraconics()
.map(draconic => {
let draconicLecture = foundry.utils.duplicate(draconic);
draconicLecture.system.defaut_carac = "intellect";
return draconicLecture;
let draconicLecture = foundry.utils.duplicate(draconic)
draconicLecture.system.defaut_carac = "intellect"
return draconicLecture
});
const intellect = this.system.carac.intellect;
@@ -2210,7 +2256,7 @@ export class RdDActor extends RdDBaseActorSang {
const xpCompetence = competence ? xp - xpCarac : 0;
if (jetResistance) {
const message = `Jet de résistance ${jetResistance}, l'expérience est limitée à 1`;
const message = `Jet de résistance, l'expérience est limitée à 1`;
ui.notifications.info(message);
console.log(message)
// max 1 xp sur jets de résistance
@@ -2278,13 +2324,12 @@ export class RdDActor extends RdDBaseActorSang {
static _getComposantsCaracDerivee(caracName) {
switch (Grammar.toLowerCaseNoAccent(caracName)) {
case 'reve-actuel': case 'reve actuel': return ['reve']
case 'chance-actuelle': case 'chance actuelle': return ['chance']
case 'vie': return ['constitution']
case 'tir': return ['vue', 'dexterite']
case 'lancer': return ['force', 'dexterite', 'vue']
case 'melee': return ['force', 'agilite']
case 'derobee': return ['agilite']
case CARACS.REVE_ACTUEL: case 'reve actuel': return [CARACS.REVE]
case CARACS.CHANCE_ACTUELLE: case 'chance actuelle': return [CARACS.CHANCE]
case CARACS.TIR: return [CARACS.DEXTERITE, CARACS.VUE]
case CARACS.LANCER: return [CARACS.FORCE, CARACS.DEXTERITE, CARACS.VUE]
case CARACS.MELEE: return [CARACS.FORCE, CARACS.AGILITE]
case CARACS.DEROBEE: return [CARACS.AGILITE]
}
return []
}
@@ -2352,14 +2397,15 @@ export class RdDActor extends RdDBaseActorSang {
if (this.tmrApp) {
ui.notifications.warn("Vous êtes déja dans les TMR....")
this.tmrApp.forceTMRDisplay()
return
return false
}
if (mode != 'visu' && this.isDemiReve()) {
ui.notifications.warn("Les personnage est déjà dans les Terres Médianes, elles s'affichent en visualisation")
ui.notifications.warn("Le personnage est déjà dans les Terres Médianes, elles s'affichent en visualisation")
mode = "visu"; // bascule le mode en visu automatiquement
}
if (mode == 'visu') {
await this._doDisplayTMR(mode)
return false
}
else {
const rencontre = this.getRencontreTMREnAttente();
@@ -2372,6 +2418,7 @@ export class RdDActor extends RdDBaseActorSang {
buttonLabel: 'Monter dans les TMR',
onAction: async () => await this._doDisplayTMR(mode)
})
return true
}
}
@@ -2394,7 +2441,7 @@ export class RdDActor extends RdDBaseActorSang {
let tmrFormData = {
mode: mode,
fatigue: RdDUtility.calculFatigueHtml(fatigue, endurance),
draconic: this.getDraconicList(),
draconic: this.getDraconics(),
sort: this.itemTypes['sort'],
signes: this.itemTypes['signedraconique'],
caracReve: parseInt(this.system.carac.reve.value),
@@ -2409,6 +2456,29 @@ export class RdDActor extends RdDBaseActorSang {
await this.tmrApp.onDeplacement()
}
async quitterTMR(message, viewOnly, cumulFatigue) {
if (this.tmrApp) {
this.tmrApp = undefined
const appliquerFatigue = ReglesOptionnelles.isUsing("appliquer-fatigue");
await this.santeIncDec(
appliquerFatigue ? "fatigue" : "endurance",
(appliquerFatigue ? 1 : -1) * cumulFatigue)
if (!viewOnly) {
await this.supprimerSignesDraconiques(it => it.system.ephemere && it.system.duree == '1 round', { render: false })
await this.setEffect(STATUSES.StatusDemiReve, false)
ChatUtility.tellToUserAndGM(message)
}
}
}
async supprimerSignesDraconiques(filter = it => true, options = { render: true }) {
const signes = this.itemTypes[ITEM_TYPES.signedraconique].filter(filter)
if (signes.length > 0) {
this.deleteEmbeddedDocuments("Item", signes.map(item => item.id), options)
}
}
/* -------------------------------------------- */
async rollSoins(blesse, blessureId) {
const blessure = blesse.blessuresASoigner().find(it => it.id == blessureId);
@@ -2416,14 +2486,17 @@ export class RdDActor extends RdDBaseActorSang {
if (!blessure.system.premierssoins.done) {
const tache = await this.getTacheBlessure(blesse, blessure);
return await this.rollTache(tache.id, {
onRollAutomate: async r => blesse.onRollTachePremiersSoins(blessureId, r)
onRollAutomate: async r => blesse.onRollTachePremiersSoins(blessureId, r),
title: 'Premiers soins',
forced: true
});
}
if (!blessure.system.soinscomplets.done) {
else if (!blessure.system.soinscomplets.done) {
const diff = blessure.system.difficulte + (blessure.system.premierssoins.bonus ?? 0);
return await this.rollCaracCompetence("dexterite", "Chirurgie", diff, {
return await this.rollCaracCompetence(CARACS.DEXTERITE, "Chirurgie", diff, {
title: "Soins complets",
onRollAutomate: r => blesse.onRollSoinsComplets(blessureId, r)
onRollAutomate: r => blesse.onRollSoinsComplets(blessureId, r),
forced: true
})
}
}
@@ -2438,6 +2511,7 @@ export class RdDActor extends RdDBaseActorSang {
})
}
const blessure = this.getItem(blessureId, 'blessure')
if (blessure && !blessure.system.premierssoins.done) {
const tache = rollData.tache;
if (rollData.rolled.isETotal) {
@@ -2508,36 +2582,34 @@ export class RdDActor extends RdDBaseActorSang {
if (item?.isEquipable()) {
const isEquipe = !item.system.equipe;
await item.update({ "system.equipe": isEquipe });
this.computeEncTotal();
this.computeEncTotal()
if (isEquipe)
this.verifierForceMin(item);
}
}
/* -------------------------------------------- */
async computeArmure(attackerRoll) {
let dmg = (attackerRoll.dmg.dmgArme ?? 0) + (attackerRoll.dmg.dmgActor ?? 0);
let armeData = attackerRoll.arme;
async computeArmure(dmg) {
let baseDmg = (dmg.dmgArme ?? 0) + (dmg.dmgActor ?? 0);
let protection = 0;
const armures = this.items.filter(it => it.type == "armure" && it.system.equipe);
for (const armure of armures) {
protection += await RdDDice.rollTotal(armure.system.protection.toString());
if (dmg > 0 && attackerRoll.dmg.encaisserSpecial != "noarmure") {
await armure.deteriorerArmure(dmg)
dmg = 0;
if (dmg.encaisserSpecial != "noarmure") {
const armures = this.items.filter(it => it.type == "armure" && it.system.equipe)
for (const armure of armures) {
protection += await RdDDice.rollTotal(armure.system.protection.toString());
if (baseDmg > 0 && dmg.encaisserSpecial != "noarmure") {
await armure.deteriorerArmure(baseDmg)
baseDmg = 0;
}
}
protection -= Math.min(dmg.penetration, protection)
protection += this.getProtectionNaturelle();
// Gestion des cas particuliers sur la fenêtre d'encaissement
if (dmg.encaisserSpecial == "chute") {
protection = Math.min(protection, 2);
}
}
const penetration = Misc.toInt(armeData?.system.penetration ?? 0);
protection = Math.max(protection - penetration, 0);
protection += this.getProtectionNaturelle();
// Gestion des cas particuliers sur la fenêtre d'encaissement
if (attackerRoll.dmg.encaisserSpecial == "noarmure") {
protection = 0;
}
if (attackerRoll.dmg.encaisserSpecial == "chute") {
protection = Math.min(protection, 2);
}
console.log("Final protect", protection, attackerRoll);
console.log("Final protect", protection, dmg)
return protection;
}
@@ -2901,6 +2973,7 @@ export class RdDActor extends RdDBaseActorSang {
if (updatedEndurance && options.diff) {
await this.setEffect(STATUSES.StatusUnconscious, updatedEndurance.value == 0)
}
await super.onUpdateActor(update, options, actorId)
}
/* -------------------------------------------- */
@@ -2920,7 +2993,9 @@ export class RdDActor extends RdDBaseActorSang {
break
case ITEM_TYPES.race:
await this.onCreateOwnedRace(item, options, id)
break
}
await super.onCreateItem(item, options, id)
await item.onCreateItemTemporel(this);
await item.onCreateDecoupeComestible(this);
}
@@ -2941,9 +3016,12 @@ export class RdDActor extends RdDBaseActorSang {
break
case ITEM_TYPES.empoignade:
await RdDEmpoignade.deleteLinkedEmpoignade(this.id, item)
// TODO: check remaining emp.
await this.setEffect(STATUSES.StatusGrappled, false)
await this.setEffect(STATUSES.StatusGrappling, false)
break
}
super.onDeleteItem(item, options, id)
await super.onDeleteItem(item, options, id)
}
/* -------------------------------------------- */
@@ -3051,40 +3129,17 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async _rollArtV2(oeuvreId, callbackAction = async (actor, rd) => await actor._resultArtV2(rd)) {
async _rollArtV2(oeuvreId) {
const oeuvre = this.items.get(oeuvreId)
const rollData = {
title: `Interpretation de ${oeuvre.name} par ${this.name}`,
mode: {
allowed: ["oeuvre"]
},
selected: {
mode: "oeuvre",
oeuvre: { key: oeuvre.id },
},
ids: {
actorId: this.id
}
ids: { actorId: this.id },
selected: { oeuvre: { key: oeuvre.id } },
type: { allowed: [PART_OEUVRE], current: PART_OEUVRE, },
}
await RollDialog.create(rollData, {
onRoll: (dialog) => {
this._onCloseRollDialog(),
dialog.close()
},
customChatMessage: true,
callbacks: [callbackAction]
})
return await RollDialog.create(rollData)
}
async _resultArtV2(artData) {
const niveau = artData.oeuvre.system.niveau ?? 0;
const baseQualite = (artData.rolled.isSuccess ? niveau : artData.competence.system.niveau);
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite;
await RdDRollResult.displayRollData(artData, this.name, `chat-resultat-${artData.art}.hbs`);
}
/* -------------------------------------------- */
async rollOeuvre(id) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
return await this._rollArtV2(id)
@@ -3170,28 +3225,39 @@ export class RdDActor extends RdDBaseActorSang {
async _resultArt(artData) {
const niveau = artData.oeuvre.system.niveau ?? 0;
const baseQualite = (artData.rolled.isSuccess ? niveau : artData.competence.system.niveau);
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite;
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite
await RdDRollResult.displayRollData(artData, this.name, `chat-resultat-${artData.art}.hbs`);
}
/* -------------------------------------------- */
async rollRecetteCuisine(id) {
const oeuvre = this.getRecetteCuisine(id);
const recette = this.getRecetteCuisine(id);
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: { allowed: [PART_CUISINE], current: PART_CUISINE },
selected: {
cuisine: { key: recette.id }
}
}
return await RollDialog.create(rollData)
}
const artData = {
verbe: 'Cuisiner',
compName: 'cuisine',
proportions: 1,
ajouterEquipement: false
};
await this._rollArtV1(artData, 'odoratgout', oeuvre, r => this._resultRecetteCuisine(r));
await this._rollArtV1(artData, 'odoratgout', recette, r => this._resultRecetteCuisine(r));
}
/* -------------------------------------------- */
async _resultRecetteCuisine(cuisine) {
const niveauRecette = cuisine.oeuvre.system.niveau ?? 0;
const baseQualite = (cuisine.rolled.isSuccess ? niveauRecette : cuisine.competence.system.niveau);
cuisine.qualiteFinale = Math.min(baseQualite, niveauRecette) + cuisine.rolled.ptQualite;
cuisine.qualiteFinale = Math.min(baseQualite, niveauRecette) + cuisine.rolled.ptQualite
cuisine.exotismeFinal = Math.min(Math.min(cuisine.qualiteFinale, cuisine.oeuvre.system.exotisme ?? 0), 0);
cuisine.sust = cuisine.oeuvre.system.sust * Math.min(cuisine.proportions, cuisine.proportionsMax ?? cuisine.proportions)
const platCuisine = {
@@ -3217,6 +3283,17 @@ export class RdDActor extends RdDBaseActorSang {
}
async preparerNourriture(item) {
if (item.getUtilisationCuisine() == 'brut' && OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: { allowed: [PART_CUISINE], current: PART_CUISINE },
selected: {
cuisine: { key: item.id }
}
}
return await RollDialog.create(rollData)
}
if (item.getUtilisationCuisine() == 'brut') {
const nourriture = {
name: 'Plat de ' + item.name,
@@ -3227,7 +3304,7 @@ export class RdDActor extends RdDBaseActorSang {
exotisme: item.system.exotisme,
ingredients: item.name
}
};
}
const artData = {
verbe: 'Préparer',
compName: 'cuisine',
@@ -3249,3 +3326,4 @@ export class RdDActor extends RdDBaseActorSang {
}
}
+6 -4
View File
@@ -56,13 +56,15 @@ export class RdDBaseActorReveSheet extends RdDBaseActorSheet {
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.", "")
await this.actor.updateCarac(caracName, parseInt(event.target.value))
});
if (event.currentTarget.name.includes("carac.")) {
let caracName = event.currentTarget.name.replace("carac.", "")
await this.actor.updateCarac(caracName, parseInt(event.currentTarget.value))
}
})
// On competence change
this.html.find('.competence-value').change(async event => {
let compName = event.currentTarget.attributes.compname.value
await this.actor.updateCompetence(compName, parseInt(event.target.value))
await this.actor.updateCompetence(compName, parseInt(event.currentTarget.value))
});
}
}
+180 -80
View File
@@ -1,4 +1,4 @@
import { ENTITE_INCARNE, SHOW_DICE, SYSTEM_RDD } from "../constants.js";
import { renderTemplate, SHOW_DICE, SYSTEM_RDD } from "../constants.js";
import { Grammar } from "../grammar.js";
import { Misc } from "../misc.js";
import { RdDResolutionTable } from "../rdd-resolution-table.js";
@@ -11,12 +11,11 @@ import { ITEM_TYPES } from "../constants.js";
import { StatusEffects, STATUSES } from "../settings/status-effects.js";
import { Targets } from "../targets.js";
import { RdDConfirm } from "../rdd-confirm.js";
import { RdDCarac } from "../rdd-carac.js";
import { CARACS, RdDCarac } from "../rdd-carac.js";
import { RdDRollResult } from "../rdd-roll-result.js";
import { RdDItemCompetence } from "../item-competence.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
import { RdDItemArme } from "../item/arme.js";
import { RdDItemCompetence } from "../item-competence.js";
import { ChatUtility } from "../chat-utility.js";
import { DialogValidationEncaissement } from "../dialog-validation-encaissement.js";
@@ -24,7 +23,12 @@ 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";
import { RollDataAjustements } from "../rolldata-ajustements-v1.js";
import { MappingCreatureArme } from "../item/mapping-creature-arme.mjs";
import RollDialog from "../roll/roll-dialog.mjs";
import { ATTAQUE_ROLL_TYPES, DEFAULT_ROLL_TYPES, DIFF, DIFFS, ROLL_TYPE_ATTAQUE, ROLL_TYPE_COMP, ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_OEUVRE, ROLL_TYPE_TACHE } from "../roll/roll-constants.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2 } from "../settings/options-avancees.js";
import { PART_COMP } from "../roll/roll-part-comp.mjs";
/**
* Classe de base pour les acteurs disposant de rêve (donc, pas des objets)
@@ -80,12 +84,11 @@ export class RdDBaseActorReve extends RdDBaseActor {
getBonusDegat() { return RdDCarac.getCaracDerivee(this.getEncombrementMax()).plusdom }
getMoralTotal() { return 0 }
listeAmoureux() {return []}
listeAmoureux() { return [] }
getProtectionNaturelle() { return Number(this.system.attributs?.protection?.value ?? 0) }
getSConst() { return 0 }
/* -------------------------------------------- */
isSurenc() { return false }
computeMalusSurEncombrement() { return 0 }
ajustementAstrologique() { return 0 }
@@ -113,16 +116,17 @@ export class RdDBaseActorReve extends RdDBaseActor {
listActions({ isAttaque = false, isEquipe = false }) {
return this.itemTypes[ITEM_TYPES.competencecreature]
.filter(it => RdDItemCompetenceCreature.isAttaque(it))
.map(it => RdDItemCompetenceCreature.attaqueCreature(it))
.filter(it => it.isAttaque())
.map(it => it.attaqueCreature())
.filter(it => it != undefined);
}
async computeArmure(attackerRoll) { return this.getProtectionNaturelle() }
async computeArmure(dmg) { return this.getProtectionNaturelle() }
async remiseANeuf() { }
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { }
computeResumeBlessure() { }
countBlessures(filter = it => !it.isContusion()) { return 0 }
async santeIncDec(name, inc, isCritique = false) { }
async finDeRound(options = { terminer: false }) {
@@ -153,11 +157,9 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
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
))
await Promise.all(this.itemTypes[ITEM_TYPES.empoignade]
.filter(it => it.system.pointsemp >= 2 && it.system.empoigneurid == this.id)
.map(async it => await RdDEmpoignade.onImmobilisation(this, it)))
}
async setSonne(sonne = true) { }
@@ -173,10 +175,11 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
getCompetences(name = undefined, options = { onMessage: message => { } }) {
const all = [...this.itemTypes[ITEM_TYPES.competence], ...this.itemTypes[ITEM_TYPES.competencecreature]]
if (name == undefined) {
return this.itemTypes[ITEM_TYPES.competence]
return all
}
return RdDItemCompetence.findCompetences(this.itemTypes[ITEM_TYPES.competence], name, options)
return RdDItemCompetence.findCompetences(all, name, options)
}
getCompetenceCorpsACorps(options = { onMessage: message => { } }) {
@@ -191,11 +194,16 @@ export class RdDBaseActorReve extends RdDBaseActor {
return RdDItemArme.getArme(armeParadeId ? this.getEmbeddedDocument('Item', armeParadeId) : undefined)
}
isForceInsuffisante(forceRequise) {
return false
}
getDraconicOuPossession() { return POSSESSION_SANS_DRACONIC }
getPossession(possessionId) {
return this.itemTypes[ITEM_TYPES.possession].find(it => it.system.possessionid == possessionId);
}
getEmpoignades() {
return this.itemTypes[ITEM_TYPES.empoignade];
}
@@ -219,51 +227,13 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
}
/* -------------------------------------------- */
isEffectAllowed(effectId) { return false }
getEffects(filter = e => true) {
return this.getEmbeddedCollection("ActiveEffect").filter(filter);
}
getEffectByStatus(statusId) {
return this.getEffects().find(it => it.statuses.has(statusId));
}
async setEffect(statusId, status) {
if (this.isEffectAllowed(statusId)) {
const effect = this.getEffectByStatus(statusId);
if (!status && effect) {
await this.deleteEmbeddedDocuments('ActiveEffect', [effect.id]);
}
if (status && !effect) {
await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(statusId)]);
}
}
}
async removeEffect(id) {
this.removeEffects(it => it.id == id)
}
async removeEffects(filter = e => true) {
if (game.user.isGM) {
const ids = this.getEffects(filter).map(it => it.id);
await this.deleteEmbeddedDocuments('ActiveEffect', ids);
}
}
/* -------------------------------------------- */
isDemiReve() {
return this.getEffectByStatus(STATUSES.StatusDemiReve) != undefined
return this.getEffectsByStatus(STATUSES.StatusDemiReve).length > 0
}
getSurprise(isCombat = undefined) {
return StatusEffects.typeSurprise(
this.getEffects()
.map(it => StatusEffects.niveauSurprise(it, isCombat))
.reduce(Misc.sum(), 0)
)
getSurprise(isCombat = undefined, forceRequise = undefined) {
return StatusEffects.getSurprise(this.getEffects(e => true, isCombat, forceRequise), isCombat)
}
/* -------------------------------------------- */
@@ -300,6 +270,21 @@ export class RdDBaseActorReve extends RdDBaseActor {
async rollCaracCompetence(caracName, compName, diff, options = { title: "" }) {
RdDEmpoignade.checkEmpoignadeEnCours(this)
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const competence = this.getCompetence(compName);
const rollData = {
ids: { actorId: this.id },
type: { allowed: DEFAULT_ROLL_TYPES, current: PART_COMP },
selected: {
carac: { key: caracName },
comp: { key: competence.name },
diff: { value: diff }
}
}
return await RollDialog.create(rollData, options)
}
const competence = this.getCompetence(compName);
await this.openRollDialog({
name: 'jet-competence',
@@ -371,10 +356,47 @@ export class RdDBaseActorReve extends RdDBaseActor {
})
}
/* -------------------------------------------- */
async rollReveActuel({ diff = 0, resistance = false }) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: {
allowed: [PART_COMP],
current: PART_COMP,
resistance: resistance
},
selected: {
carac: { key: CARACS.REVE_ACTUEL, forced: true },
comp: resistance ? { key: undefined, forced: true } : undefined,
diff: { type: DIFF.DEFAUT, value: diff }
}
}
return await RollDialog.create(rollData)
}
return this.rollCarac(CARACS.REVE_ACTUEL, { diff, resistance })
}
async rollCarac(caracName, options = {}) {
if (Grammar.equalsInsensitive(caracName, 'taille')) {
if (Grammar.equalsInsensitive(caracName, CARACS.TAILLE)) {
return
}
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: {
allowed: options.resistance ? [PART_COMP] : DEFAULT_ROLL_TYPES,
current: PART_COMP,
resistance: options.resistance
},
selected: {
carac: { key: caracName },
comp: options.resistance ? { key: undefined, forced: true } : undefined,
diff: { type: DIFF.DEFAUT, value: options.diff ?? 0 }
}
}
return await RollDialog.create(rollData, options)
}
foundry.utils.mergeObject(options, { resistance: false, diff: 0 }, { overwrite: false })
RdDEmpoignade.checkEmpoignadeEnCours(this)
let selectedCarac = this.getCaracByName(caracName)
@@ -401,10 +423,24 @@ export class RdDBaseActorReve extends RdDBaseActor {
await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-general.hbs');
}
/* -------------------------------------------- */
async rollCompetence(idOrName, options = { tryTarget: true, arme: undefined }) {
RdDEmpoignade.checkEmpoignadeEnCours(this)
const competence = this.getCompetence(idOrName);
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: { allowed: options.arme ? ATTAQUE_ROLL_TYPES : DEFAULT_ROLL_TYPES },
selected: {
carac: competence.type == ITEM_TYPES.competencecreature ? { key: competence.name } : undefined,
comp: { key: competence.name },
diff: { type: options.arme ? DIFF.ATTAQUE : DIFF.LIBRE, value: competence.system.default_diffLibre ?? 0 },
attaque: options.arme ? { arme: { key: options.arme.id } } : undefined
}
}
return await RollDialog.create(rollData)
}
let rollData = {
carac: this.system.carac,
competence: competence,
@@ -412,7 +448,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
if (competence.type == ITEM_TYPES.competencecreature) {
const token = RdDUtility.getSelectedToken(this)
const arme = RdDItemCompetenceCreature.armeCreature(competence)
const arme = MappingCreatureArme.armeCreature(competence)
if (arme && options.tryTarget && Targets.hasTargets()) {
Targets.selectOneTargetToken(target => {
if (arme.action == "possession") {
@@ -422,10 +458,10 @@ export class RdDBaseActorReve extends RdDBaseActor {
RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme)
}
});
return;
return
}
// Transformer la competence de créature
RdDItemCompetenceCreature.setRollDataCreature(rollData)
MappingCreatureArme.setRollDataCreature(rollData)
}
const dialogLabel = 'Jet ' + Grammar.apostrophe('de', competence.name);
await this.openRollDialog({
@@ -444,16 +480,50 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
}
rollAttaque(token) {
token = token ?? RdDUtility.getSelectedToken(this)
if (Targets.hasTargets()) {
Targets.selectOneTargetToken(target => {
if (Targets.isTargetEntite(target)) {
ui.notifications.warn(`Vous ne pouvez pas attaquer une entité non incarnée!!!!`)
return
}
RdDCombat.rddCombatTarget(target, this, token).attaqueV2();
})
}
else {
return RdDConfirm.confirmer({
settingConfirmer: "confirmer-combat-sans-cible",
content: `<p>Voulez vous faire une attaque sans choisir de cible valide?
<br>Tous les jets de combats devront être gérés à la main
</p>`,
title: 'Ne pas utiliser les automatisation de combat',
buttonLabel: "Pas d'automatisation",
onAction: async () => {
const rollData = {
ids: { actorId: this.id, actorTokenId: token?.id, },
type: {
allowed: [ROLL_TYPE_ATTAQUE], current: ROLL_TYPE_ATTAQUE
}
};
return await RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose })
}
})
}
}
/** --------------------------------------------
* @param {*} arme item d'arme/compétence de créature
* @param {*} categorieArme catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession
* @returns
* @returns
*/
rollArme(arme, categorieArme = 'competence', token = undefined) {
token = token ?? RdDUtility.getSelectedToken(this)
const compToUse = RdDItemArme.getCompetenceArme(arme, categorieArme)
if (!RdDItemArme.isUtilisable(arme)) {
ui.notifications.warn(`Arme inutilisable: ${arme.name} a une résistance de 0 ou moins`)
ui.notifications.warn(`Arme inutilisable: ${arme.name} non équipée ou avec une résistance de 0 ou moins`)
return
}
if (!Targets.hasTargets()) {
@@ -490,29 +560,37 @@ export class RdDBaseActorReve extends RdDBaseActor {
/* -------------------------------------------- */
async encaisser() { await RdDEncaisser.encaisser(this) }
async encaisserDommages(rollData, attacker = undefined, show = undefined, attackerToken = undefined, defenderToken = undefined) {
async encaisserDommages(dmg, attacker = undefined, show = undefined, attackerToken = undefined, defenderToken = undefined) {
if (attacker && !await attacker.accorder(this, 'avant-encaissement')) {
return;
return
}
const armure = await this.computeArmure(rollData);
if (!Misc.isOwnerPlayer(this)) {
return RdDBaseActor.remoteActorCall({
tokenId: attackerToken?.id ?? this.token?.id,
actorId: this.id,
method: 'encaisserDommages', args: [dmg, attacker, show, attackerToken, defenderToken]
})
}
const armure = await this.computeArmure(dmg)
if (ReglesOptionnelles.isUsing('validation-encaissement-gr')) {
await this.encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken);
await this.encaisserDommagesValidationGR(dmg, armure, show, attackerToken, defenderToken);
}
else {
const jet = await RdDUtility.jetEncaissement(this, rollData, armure, { showDice: SHOW_DICE });
const jet = await RdDUtility.jetEncaissement(this, dmg, armure, { showDice: SHOW_DICE });
await this.$onEncaissement(jet, show, attackerToken, defenderToken)
}
}
async encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken) {
async encaisserDommagesValidationGR(dmg, armure, show, attackerToken, defenderToken) {
if (!game.user.isGM) {
RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
method: 'encaisserDommagesValidationGR', args: [rollData, armure, show, attackerToken, defenderToken]
method: 'encaisserDommagesValidationGR', args: [dmg, armure, show, attackerToken, defenderToken]
})
} else {
DialogValidationEncaissement.validerEncaissement(this, rollData, armure,
DialogValidationEncaissement.validerEncaissement(this, dmg, armure,
jet => this.$onEncaissement(jet, show, attackerToken, defenderToken));
}
}
@@ -549,15 +627,37 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
}
async encaisserRecul(force, dmgArme = 0) {
const diffRecul = this.getTaille() - force - dmgArme
const rolled = await RdDResolutionTable.roll(10, diffRecul)
if (rolled.isSuccess) {
return 'encaisse'
}
if (rolled.isETotal || (await this.rollEquilibre(diffRecul)).isEchec) {
await this.setEffect(STATUSES.StatusProne, true)
return 'chute'
}
return 'recul'
}
/* -------------------------------------------- */
async rollEquilibre(diff) {
// TODO: accrobatie optionnelle sur jet d'équilibre?
if (ReglesOptionnelles.isSet('acrobatie-pour-recul')) {
diff += Math.max(0, this.getCompetence('acrobatie')?.system.niveau ?? 0)
}
return await RdDResolutionTable.roll(this.getAgilite(), diff);
}
/* -------------------------------------------- */
async accorder(entite, when = 'avant-encaissement') {
if (when != game.settings.get(SYSTEM_RDD, "accorder-entite-cauchemar")
|| entite == undefined
|| !entite.isEntite([ENTITE_INCARNE])
|| !entite.isEntiteIncarnee()
|| entite.isEntiteAccordee(this)) {
return true;
return true
}
const rolled = await RdDResolutionTable.roll(this.getReveActuel(), - Number(entite.getNiveau()));
const rolled = await RdDResolutionTable.roll(this.getReveActuel(), - Number(entite.getNiveau()))
const rollData = {
alias: this.getAlias(),
rolled: rolled,
@@ -566,11 +666,11 @@ export class RdDBaseActorReve extends RdDBaseActor {
};
if (rolled.isSuccess) {
await entite.setEntiteReveAccordee(this);
await entite.setEntiteReveAccordee(this)
}
await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-accorder-cauchemar.hbs');
await this.appliquerAjoutExperience(rollData, true);
await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-accorder-cauchemar.hbs')
await this.appliquerAjoutExperience(rollData, true)
return rolled.isSuccess;
}
+61 -18
View File
@@ -34,17 +34,17 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
getFatigueActuelle() {
if (ReglesOptionnelles.isUsing("appliquer-fatigue")) {
return Math.max(0, Math.min(this.getFatigueMax(), Misc.toInt(this.system.sante.fatigue?.value)))
return Math.max(0, Math.min(this.getFatigueMax(), Misc.toInt(this.system.sante.fatigue?.value)))
}
return 0;
}
isCumulFatigueCauseSommeil(cumulFatigue){
isCumulFatigueCauseSommeil(cumulFatigue) {
return ReglesOptionnelles.isUsing("appliquer-fatigue")
? (this.getFatigueRestante() <= cumulFatigue)
: (this.getEnduranceActuelle() <= cumulFatigue)
? (this.getFatigueRestante() <= cumulFatigue)
: (this.getEnduranceActuelle() <= cumulFatigue)
}
getFatigueRestante() {return this.getFatigueMax() - this.getFatigueActuelle() }
getFatigueRestante() { return this.getFatigueMax() - this.getFatigueActuelle() }
getFatigueMin() { return this.system.sante.endurance.max - this.system.sante.endurance.value }
malusFatigue() {
@@ -116,6 +116,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
blessure: blessure
});
}
/* -------------------------------------------- */
async santeIncDec(name, inc, isCritique = false) {
if (name == 'fatigue' && !ReglesOptionnelles.isUsing("appliquer-fatigue")) {
@@ -129,7 +130,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
let result = {
sonne: false,
};
let perteEndurance = 0
let minValue = name == "vie" ? -this.getSConst() - 1 : 0;
result.newValue = Math.max(minValue, Math.min(compteur.value + inc, compteur.max));
@@ -144,16 +145,10 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
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);
}
perteEndurance = compteur.value - result.newValue;
result.perte = perteEndurance
if (sante.fatigue && inc < 0) { // Each endurance lost -> fatigue lost
fatigue = perte;
fatigue = perteEndurance;
}
}
compteur.value = result.newValue;
@@ -161,7 +156,15 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
if (ReglesOptionnelles.isUsing("appliquer-fatigue") && sante.fatigue && fatigue > 0) {
sante.fatigue.value = Math.max(sante.fatigue.value + fatigue, this.getFatigueMin());
}
await this.update({ "system.sante": sante })
await this.update({ "system.sante": sante }, { render: true })
if (perteEndurance > 1) {
// Peut-être sonné si 2 points d'endurance perdus d'un coup
foundry.utils.mergeObject(result, await this.jetEndurance(result.newValue));
} else if (name == "endurance" && inc > 0) {
await this.setSonne(false);
}
if (this.isDead()) {
await this.setEffect(STATUSES.StatusComma, true);
}
@@ -179,6 +182,46 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
return Math.max(0, Math.min(maxEndVie, maxEndGraves, maxEndCritiques));
}
async onCreateItem(item, options, id) {
await this.changeItemEffects(item)
await super.onCreateItem(item, options, id)
}
async onUpdateItem(item, options, id) {
await this.changeItemEffects(item);
await super.onUpdateItem(item, options, id)
}
async onDeleteItem(item, options, id) {
await this.changeItemEffects(item);
await super.onDeleteItem(item, options, id)
}
async changeItemEffects(item) {
switch (item.type) {
case ITEM_TYPES.blessure:
await this.changeStateBleeding();
break;
case ITEM_TYPES.maladie:
case ITEM_TYPES.poison:
await this.changeStateMalade();
break;
}
}
async changeStateBleeding() {
const bleeding = this.itemTypes[ITEM_TYPES.blessure].find(it => it.isBleeding())
await this.setEffect(STATUSES.StatusBleeding, bleeding ? true : false)
}
async changeStateMalade() {
const maladiePoisons = this.getMaladiesPoisons()
await this.setEffect(STATUSES.StatusMalade, maladiePoisons.length > 0)
}
getMaladiesPoisons() {
return this.items.filter(it => [ITEM_TYPES.maladie, ITEM_TYPES.poison].includes(it.type))
}
/* -------------------------------------------- */
async ajouterBlessure(encaissement, attackerToken = undefined) {
@@ -195,7 +238,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
const endActuelle = this.getEnduranceActuelle();
const blessure = await RdDItemBlessure.createBlessure(this, encaissement.gravite, encaissement.dmg?.loc.label ?? '', attackerToken);
if (blessure.isCritique()) {
encaissement.endurance = endActuelle;
encaissement.endurance = endActuelle
}
if (blessure.isMort()) {
@@ -292,7 +335,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
}
isSonne() {
return this.getEffectByStatus(STATUSES.StatusStunned)
return this.getEffectsByStatus(STATUSES.StatusStunned).length > 0
}
isEffectAllowed(effectId) { return true }
+3 -11
View File
@@ -5,9 +5,9 @@ import { RdDSheetUtility } from "../rdd-sheet-utility.js";
import { Monnaie } from "../item-monnaie.js";
import { ITEM_TYPES } from "../constants.js";
import { RdDItem } from "../item.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js";
import { ItemAction } from "../item/item-actions.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
/* -------------------------------------------- */
/**
@@ -49,14 +49,14 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet {
formData.calc = {
fortune: Monnaie.toSolsDeniers(this.actor.getFortune()),
prixTotalEquipement: this.actor.computePrixTotalEquipement(),
encTotal: await this.actor.computeEncTotal(),
encTotal: this.actor.getEncTotal(),
}
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))
.forEach(it => it.isdommages = it.isDommages())
return formData;
}
@@ -229,14 +229,6 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet {
return position;
}
/* -------------------------------------------- */
/** @override */
_updateObject(event, formData) {
// Update the Actor
return this.actor.update(formData);
}
async splitItem(item) {
const dialog = await DialogSplitItem.create(item, (item, split) => this._onSplitItem(item, split));
dialog.render(true);
+102 -15
View File
@@ -1,6 +1,6 @@
import { ChatVente } from "../achat-vente/chat-vente.js";
import { ChatUtility } from "../chat-utility.js";
import { SYSTEM_SOCKET_ID } from "../constants.js";
import { renderTemplate, SYSTEM_SOCKET_ID } from "../constants.js";
import { Grammar } from "../grammar.js";
import { Monnaie } from "../item-monnaie.js";
import { ITEM_TYPES } from "../constants.js";
@@ -9,6 +9,8 @@ import { RdDAudio } from "../rdd-audio.js";
import { RdDConfirm } from "../rdd-confirm.js";
import { RdDUtility } from "../rdd-utility.js";
import { SystemCompendiums } from "../settings/system-compendiums.js";
import { RdDItem } from "../item.js";
import { StatusEffects, STATUSES } from "../settings/status-effects.js";
export class RdDBaseActor extends Actor {
@@ -44,8 +46,10 @@ export class RdDBaseActor extends Actor {
}
static init() {
Handlebars.registerHelper('actor-isFeminin', actor => actor.isFeminin())
Hooks.on("preUpdateItem", (item, change, options, id) => Misc.documentIfResponsible(item.parent)?.onPreUpdateItem(item, change, options, id))
Hooks.on("createItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onCreateItem(item, options, id))
Hooks.on("updateItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onUpdateItem(item, options, id))
Hooks.on("deleteItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onDeleteItem(item, options, id))
Hooks.on("updateActor", (actor, change, options, actorId) => Misc.documentIfResponsible(actor)?.onUpdateActor(change, options, actorId))
}
@@ -211,12 +215,15 @@ export class RdDBaseActor extends Actor {
return game.users.players.find(player => player.active && player.character?.id == this.id);
}
isCreatureEntite() { return this.isCreature() || this.isEntite() }
isCreatureOuEntite() { return this.isCreature() || this.isEntite() }
isCreature() { return false }
isEntite(typeentite = []) { return false }
isEntite() { return false }
isEntiteIncarnee() { return false }
isEntiteNonIncarnee() { return false }
isHautRevant() { return false }
isVehicule() { return false }
isPersonnage() { return false }
isFeminin() { return false }
getItem(id, type = undefined) {
const item = this.items.get(id);
if (type == undefined || (item?.type == type)) {
@@ -236,20 +243,89 @@ export class RdDBaseActor extends Actor {
getMonnaie(id) { return this.findItemLike(id, 'monnaie'); }
getEncombrementMax() { return 0 }
isSurenc() { return false }
/* -------------------------------------------- */
isEffectAllowed(effectId) { return false }
getEffects(filter = e => true, forceRequise = undefined) {
const effects = this.getEmbeddedCollection("ActiveEffect")
const selected = effects.filter(filter)
if (forceRequise && this.isForceInsuffisante(forceRequise)) {
selected.push(StatusEffects.prepareActiveEffect(STATUSES.StatusForceWeak))
}
return selected
}
getEffectsByStatus(effectId) {
return this.getEffects().filter(it => it.statuses.has(effectId))
}
async setEffect(effectId, status) {
if (this.isEffectAllowed(effectId)) {
const effects = this.getEffectsByStatus(effectId)
if (!status && effects.length > 0) {
await this.deleteEmbeddedDocuments('ActiveEffect', effects.map(it => it.id), { render: true })
}
if (status && effects.length == 0) {
await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(effectId)], { render: true })
}
}
}
async removeEffect(id) {
this.removeEffects(it => it.id == id)
}
async removeEffects(filter = e => true) {
if (game.user.isGM) {
const ids = this.getEffects(filter)
.filter(it => this.canRemoveEffects(it))
.map(it => it.id)
if (ids.length > 0) {
await this.deleteEmbeddedDocuments('ActiveEffect', ids)
}
}
}
canRemoveEffects(effect) {
if (effect.statuses.has(STATUSES.StatusSurEnc)) {
return !this.isSurenc()
}
if (effect.statuses.has(STATUSES.StatusDemiReve)) {
return !this.tmrApp
}
return true
}
/* -------------------------------------------- */
async updateCarac(caracName, to) {
}
async onUpdateActor(change, options, actorId) {
const updatedCarac = change?.system?.carac
if (updatedCarac && (updatedCarac.force || updatedCarac.reve || updatedCarac.taille)) {
console.log(' onUpdateActor', change, options, actorId)
await this.setEffect(STATUSES.StatusSurEnc, this.isSurenc())
}
}
/* -------------------------------------------- */
async onPreUpdateItem(item, change, options, id) { }
async onCreateItem(item, options, id) { }
async onUpdateActor(update, options, actorId) { }
async onCreateItem(item, options, id) {
}
async onUpdateItem(item, options, id) {
}
async onDeleteItem(item, options, id) {
if (item.isInventaire()) {
await this._removeItemFromConteneur(item)
}
}
async _removeItemFromConteneur(item) {
const updates = this.items.filter(it => it.isConteneur() && it.system.contenu.includes(item.id))
.map(conteneur => {
@@ -498,15 +574,22 @@ export class RdDBaseActor extends Actor {
/* -------------------------------------------- */
async computeEncTotal() {
if (!this.pack) {
this.encTotal = this.items.map(it => it.getEncTotal()).reduce(Misc.sum(), 0);
return this.encTotal;
if (this.pack) {
this.encTotal = 0
}
else {
const wasSurenc = this.isSurenc()
this.encTotal = this.items.filter(it => RdDItem.getItemTypesInventaire().includes(it.type))
.map(it => it.getEncTotal()).reduce(Misc.sum(), 0)
const isSurenc = this.isSurenc()
if (isSurenc != wasSurenc) {
await this.setEffect(STATUSES.StatusSurEnc, isSurenc)
}
}
return 0;
}
getEncTotal() {
return Math.floor(this.encTotal ?? 0);
return Math.floor(this.encTotal ?? 0)
}
async createItem(type, name = undefined) {
@@ -557,7 +640,7 @@ export class RdDBaseActor extends Actor {
}
}
}
await this.computeEncTotal();
await this.computeEncTotal()
return result;
}
@@ -736,7 +819,7 @@ export class RdDBaseActor extends Actor {
name: this.getAlias(),
system: { description: this.system.description }
}
foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/post-actor.hbs', chatData)
renderTemplate('systems/foundryvtt-reve-de-dragon/templates/post-actor.hbs', chatData)
.then(html => ChatMessage.create(RdDUtility.chatDataSetup(html, modeOverride)));
}
@@ -758,20 +841,24 @@ export class RdDBaseActor extends Actor {
getCaracInit(competence) { return 0 }
listAttaques() {
return this.listActions({ isAttaque: true, isEquipe:false })
return this.listActions({ isAttaque: true, isEquipe: false })
}
listActions({ isAttaque = false, isEquipe=false }) { return [] }
listActions({ isAttaque = false, isEquipe = false }) { return [] }
listActionsPossessions() {
return this.itemTypes[ITEM_TYPES.possession]
.map(p => {
return {
name: p.name,
label: p.name,
action: 'possession',
possessionid: p.system.possessionid,
}
})
}
listActionsCombat() {
const possessions = this.listActionsPossessions()
return possessions.length > 0 ? possessions : this.listActions({})
}
}
-3
View File
@@ -1,6 +1,4 @@
import { Grammar } from "../grammar.js";
import { ITEM_TYPES } from "../constants.js";
import { LIST_CARAC_AUTRES } from "../rdd-carac.js";
import { RdDBaseActorSang } from "./base-actor-sang.js";
export class RdDCreature extends RdDBaseActorSang {
@@ -45,5 +43,4 @@ export class RdDCreature extends RdDBaseActorSang {
}
return undefined
}
}
+1 -1
View File
@@ -43,7 +43,7 @@ export class RdDActorEntiteSheet extends RdDBaseActorReveSheet {
this.html.find('.resonance-add').click(async event =>
await DialogSelect.select({
label: "Choisir un acteur à accorder",
list: game.actors.filter(it => it.isPersonnage() && it.prototypeToken.actorLink)
list: game.actors.filter(it => true)
},
it => this.resonanceAdd(it.id))
)
+19 -15
View File
@@ -1,5 +1,6 @@
import { ENTITE_INCARNE, ENTITE_NONINCARNE } from "../constants.js";
import { ENTITE_BLURETTE, ENTITE_INCARNE, ENTITE_NONINCARNE } from "../constants.js";
import { ITEM_TYPES } from "../constants.js";
import { RdDItemBlessure } from "../item/blessure.js";
import { Misc } from "../misc.js";
import { RdDCarac } from "../rdd-carac.js";
import { RdDEncaisser } from "../rdd-roll-encaisser.js";
@@ -16,11 +17,10 @@ export class RdDEntite extends RdDBaseActorReve {
return item.type == ITEM_TYPES.competencecreature
}
isEntite(typeentite = []) {
return (typeentite.length == 0 || typeentite.includes(this.system.definition.typeentite));
}
isNonIncarnee() { return this.isEntite([ENTITE_NONINCARNE]) }
isEntite() { return true }
isEntiteNonIncarnee() { return this.system.definition.typeentite == ENTITE_NONINCARNE }
isEntiteIncarnee() { return [ENTITE_INCARNE, ENTITE_BLURETTE].includes(this.system.definition.typeentite) }
isEntiteBlurette() { return this.system.definition.typeentite !== ENTITE_BLURETTE }
getReveActuel() {
return Misc.toInt(this.system.carac.reve?.value)
@@ -49,20 +49,20 @@ export class RdDEntite extends RdDBaseActorReve {
}
async remiseANeuf() {
await this.removeEffects(e => true);
if (!this.isNonIncarnee()) {
if (!this.isEntiteNonIncarnee()) {
await this.update({
'system.sante.endurance.value': this.system.sante.endurance.max
});
}
await this.removeEffects(e => true)
}
isDead() {
return this.isNonIncarnee() ? false : this.system.sante.endurance.value <= 0
return this.isEntiteNonIncarnee() ? false : this.system.sante.endurance.value <= 0
}
async santeIncDec(name, inc, isCritique = false) {
if (name == 'endurance' && !this.isNonIncarnee()) {
if (name == 'endurance' && !this.isEntiteNonIncarnee()) {
const oldValue = this.system.sante.endurance.value;
const endurance = Math.max(0,
Math.min(oldValue + inc,
@@ -78,7 +78,7 @@ export class RdDEntite extends RdDBaseActorReve {
}
async encaisser() {
if (this.isNonIncarnee()) {
if (this.isEntiteNonIncarnee()) {
return
}
await RdDEncaisser.encaisser(this)
@@ -89,15 +89,19 @@ export class RdDEntite extends RdDBaseActorReve {
}
async onAppliquerJetEncaissement(encaissement, attackerToken) {
if (this.isEntiteNonIncarnee()) {
return
}
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance);
foundry.utils.mergeObject(encaissement, {
resteEndurance: perteEndurance.newValue,
endurance: perteEndurance.perte
});
endurance: perteEndurance.perte,
blessure: RdDItemBlessure.prepareBlessure(encaissement.gravite, encaissement.dmg?.loc.label ?? '', attackerToken)
})
}
isEntiteAccordee(attacker) {
if (this.isEntite([ENTITE_INCARNE])) {
if (this.isEntiteIncarnee()) {
let resonnance = this.system.sante.resonnance
return (resonnance.actors.find(it => it == attacker.id))
}
@@ -106,7 +110,7 @@ export class RdDEntite extends RdDBaseActorReve {
/* -------------------------------------------- */
async setEntiteReveAccordee(actor) {
if (this.isEntite([ENTITE_INCARNE])) {
if (this.isEntiteIncarnee()) {
if (this.system.sante.resonnance.actors.find(it => it == actor.id)) {
// déjà accordé
return
+1 -1
View File
@@ -29,7 +29,7 @@ export class ExperienceLog {
};
console.log('ExperienceLog.add', newXpLog)
const newExperienceLog = (actor.system.experiencelog ?? []).concat([newXpLog]);
await actor.update({ [`system.experiencelog`]: newExperienceLog });
await actor.update({ [`system.experiencelog`]: newExperienceLog }, { noHook: true });
}
static labelTopic(topic) {
+288
View File
@@ -0,0 +1,288 @@
import { ACTOR_TYPES, ITEM_TYPES } from "../../constants.js"
import { Grammar } from "../../grammar.js"
import { RdDItemArme } from "../../item/arme.js"
import { CATEGORIES_COMPETENCE_COMBAT } from "../../item/base-items.js"
import { Misc } from "../../misc.js"
import { RdDTimestamp } from "../../time/rdd-timestamp.js"
import { PDFDocument } from "./pdf-lib/pdf-lib.esm.js"
const copyProperty = (actor, path) => foundry.utils.getProperty(actor, path)
// const findItem = (actor, itemType, itemName) => actor.itemTypes[itemType].find(it => Grammar.equalsInsensitive(formCompName(it.name), formCompName(itemName)))
// const findItemPos = (actor, itemType, pos) => actor.itemTypes[itemType].length <= pos ? actor.itemTypes[itemType][pos] : length
// const findProperty = (it, path) => it ? foundry.utils.getProperty(it, path) : undefined
// const findItemProperty = (actor, itemType, itemName, path) => findProperty(findItem(actor, itemType, itemName), path)
// const findItemPosProperty = (actor, itemType, pos, path) => findProperty(findItemPos(actor, itemType, pos), path)
// const findArmeProperty = (actor, pos, path) => findProperty(findItemPos(actor, ITEM_TYPES.arme, pos), path)
// const findSortProperty = (actor, pos, path) => findProperty(findItemPos(actor, ITEM_TYPES.sort, pos), path)
// const itemFormPath = (type, pos, property) => `${type}s.${pos}.${property}`
const ACTOR_TO_FORM_MAPPING = [
{ path: 'name' },
{ path: 'system.carac.taille.value' },
{ path: 'system.carac.apparence.value' },
{ path: 'system.carac.apparence.xp' },
{ path: 'system.carac.constitution.value' },
{ path: 'system.carac.constitution.xp' },
{ path: 'system.carac.force.value' },
{ path: 'system.carac.force.value' },
{ path: 'system.carac.force.xp' },
{ path: 'system.carac.agilite.value' },
{ path: 'system.carac.agilite.xp' },
{ path: 'system.carac.dexterite.value' },
{ path: 'system.carac.dexterite.xp' },
{ path: 'system.carac.vue.value' },
{ path: 'system.carac.vue.xp' },
{ path: 'system.carac.ouie.value' },
{ path: 'system.carac.ouie.xp' },
{ path: 'system.carac.odoratgout.value' },
{ path: 'system.carac.odoratgout.xp' },
{ path: 'system.carac.volonte.value' },
{ path: 'system.carac.volonte.xp' },
{ path: 'system.carac.empathie.value' },
{ path: 'system.carac.empathie.xp' },
{ path: 'system.carac.intellect.value' },
{ path: 'system.carac.intellect.xp' },
{ path: 'system.carac.reve.value' },
{ path: 'system.carac.reve.xp' },
{ path: 'system.carac.chance.value' },
{ path: 'system.carac.chance.xp' },
{ path: 'system.age' },
{ path: 'system.sexe' },
{ path: 'system.taille' },
{ path: 'system.poids' },
{ path: 'system.cheveux' },
{ path: 'system.yeux' },
{ path: 'system.beaute' },
{ path: 'system.main' },
{ path: 'system.heure' },
{ path: 'computed.hn.heure', getter: actor => (RdDTimestamp.definition(actor.system.heure)?.heure ?? 0) + 1 },
{ path: 'computed.hn.label', getter: actor => RdDTimestamp.definition(actor.system.heure)?.avecArticle },
{ path: 'system.carac.melee.value' },
{ path: 'system.carac.tir.value' },
{ path: 'system.carac.lancer.value' },
{ path: 'system.carac.derobee.value' },
{ path: 'system.sante.vie.value' },
{ path: 'system.sante.endurance.value' },
{ path: 'system.attributs.sust.value' },
{ path: 'system.attributs.sconst.value' },
{ path: 'system.attributs.encombrement.value' },
{ path: 'system.attributs.plusdom.value', getter: actor => Misc.toSignedString(actor.system.attributs.plusdom.value) },
// , getter: actor => actor.get
]
export default class ExportPdf {
static init() {
Hooks.on("getActorContextOptions", (actorDirectory, menus) => { ExportPdf.onActorDirectoryMenu(actorDirectory, menus) })
}
static onActorDirectoryMenu(actorDirectory, menus) {
menus.push({
name: 'Export PDF',
icon: '<i class="fa-regular fa-file-pdf"></i>',
condition: target => actorDirectory.id == 'actors' && ExportPdf.$isActorPersonnage(this.$getActor(target)),
callback: async target => await ExportPdf.exportActor(target)
})
}
static $getActor(target) {
const entryId = $(target).closest(".directory-item")?.data("entryId")
return game.actors.get(entryId)
}
static $isActorPersonnage(actor) {
return actor?.type == ACTOR_TYPES.personnage
}
static async exportActor(target) {
const actor = ExportPdf.$getActor(target)
if (!ExportPdf.$isActorPersonnage(actor)) {
ui.notifications.error("Pas de personnage sélectionné")
return
}
const templatePdf = '/systems/foundryvtt-reve-de-dragon/assets/feuille-personnage.pdf';
const pdfBytes = await fetch(templatePdf).then(res => res.arrayBuffer())
const pdfDoc = await PDFDocument.load(pdfBytes)
const exporter = new ExportPdf(actor, pdfDoc)
exporter.generateFeuillePersonnage()
}
constructor(actor, pdfDoc) {
this.pdfDoc = pdfDoc
this.form = this.pdfDoc.getForm()
this.actor = actor
this.allComps = this.actor.itemTypes[ITEM_TYPES.competence]
this.comps = this.allComps
.filter(it => !it.isNiveauBase())
.sort(Misc.ascending(it => it.name))
this.compsNonArmes = this.comps.filter(it => !ExportPdf.isCompCombat(it))
this.compsArmes = this.comps.filter(it => ExportPdf.isCompCombat(it))
this.addedComps = new Set([])
}
static isCompCombat(comp) {
return CATEGORIES_COMPETENCE_COMBAT.includes(comp.system.categorie) && !Grammar.includesLowerCaseNoAccent(comp.name, "corps à corps") && !Grammar.includesLowerCaseNoAccent(comp.name, "esquive")
}
async generateFeuillePersonnage() {
this.$exportActorFields()
this.$exportCompetences()
this.$exportArchetype()
this.$exportArmes()
this.$exportSorts()
const pdfBytes = await this.pdfDoc.save();
const filename = `rdd-${this.actor.name.slugify()}.pdf`;
foundry.utils.saveDataToFile(pdfBytes, "application/pdf", filename);
}
$exportActorFields() {
ACTOR_TO_FORM_MAPPING.forEach(async (mapping) => {
const path = mapping.path
const value = mapping.getter ? mapping.getter(this.actor) : copyProperty(this.actor, path)
this.$setFormValue(path, value)
})
}
$exportCompetences() {
this.compsNonArmes
.filter(it => !this.addedComps.has(it.id))
.forEach(comp => {
const formCompName = Grammar.toLowerCaseNoAccent(comp.name.replaceAll(/(\s|-|\')/g, '_'))
this.$setFormCompetence(formCompName, comp)
})
const musique = this.compsNonArmes.filter(it => Grammar.includesLowerCaseNoAccent(it.name, 'musique'))
.sort(Misc.descending(it => it.system.niveau))
.filter(it => !this.addedComps.has(it.id))
.find(it => true)
if (musique) {
this.$setFormCompetence('musique', musique)
}
}
$exportArchetype() {
this.allComps.sort(Misc.ascending(it => it.system.niveau_archetype))
.forEach(comp => {
let formCompName = Grammar.toLowerCaseNoAccent(comp.name.replaceAll(/(\s|-|\')/g, '_'))
if (formCompName.includes('musique')) {
formCompName = 'musique'
}
this.$setFormValue(`competences.${formCompName}.niveau_archetype`, comp.system.niveau_archetype)
})
}
$setFormCompetenceArchetype(formCompName, comp, baseFormName = 'competences') {
}
$exportArmes() {
const uniques = new Set([])
const armes = this.actor.itemTypes[ITEM_TYPES.arme].map(arme => arme.getTypeAttaques()
.map(main => {
const compName = arme.getCompetenceAction(main)
const dommages = RdDItemArme.valeurMain(arme.system.dommages, main)
const forceRequise = RdDItemArme.valeurMain(arme.system.force ?? 0, main)
const comp = this.compsArmes.find(it => Grammar.equalsInsensitive(it.name, compName)) ?? this.actor.findItemLike(compName, ITEM_TYPES.competence)
const unique = [comp.id, arme.name, dommages, forceRequise].join('|');
if (uniques.has(unique)) {
return undefined
}
uniques.add(unique)
return { arme: arme, comp: comp, main: main }
}))
.reduce((a, b) => a.concat(b))
.filter(it => it != undefined && !it.comp.isNiveauBase())
.sort(Misc.descending(it => it.comp.niveau))
for (let pos = 0; pos < armes.length; pos++) {
const it = armes[pos]
this.$setFormArmeCompetence(pos, it.comp, it.arme, it.main, it.main)
}
// TODO: list comps without weapons
// TODO: list other comps not in the standard list -- use an instance of ExportPdf to hold state/built list
const otherComps = this.comps.filter(it => !this.addedComps.has(it.id))
for (let pos = 0; pos < otherComps.length; pos++) {
const comp = otherComps[pos]
this.$setFormCompetence(pos, comp, 'competences')
this.$setFormValue(`competences.${pos}.name`, comp.name)
}
}
$setFormCompetence(formCompName, comp, baseFormName = 'competences') {
if (this.form.getFieldMaybe(`${baseFormName}.${formCompName}.niveau`)) {
this.addedComps.add(comp.id)
}
if (comp.system.niveau != comp.system.base) {
this.$setFormValue(`${baseFormName}.${formCompName}.niveau`, comp.system.niveau)
}
if (comp.system.xp > 0) {
this.$setFormValue(`${baseFormName}.${formCompName}.xp`, comp.system.xp)
}
if (comp.system.xp_sort > 0) {
this.$setFormValue(`${baseFormName}.${formCompName}.xp_sort`, comp.system.xp_sort)
}
if (CATEGORIES_COMPETENCE_COMBAT.includes(comp.system.categorie)) {
this.$setFormValue(`${baseFormName}.${formCompName}.init`, comp.getBaseInit())
}
}
$setFormArmeCompetence(pos, comp, arme, main) {
this.$setFormCompetence(pos, comp, 'armes')
this.$setFormValue(`armes.${pos}.name`, arme.name)
this.$setFormValue(`armes.${pos}.main`, main)
this.$setFormValue(`armes.${pos}.plusdom`, RdDItemArme.valeurMain(arme.system.dommages, main))
}
$exportSorts() {
const sorts = this.actor.itemTypes[ITEM_TYPES.sort].sort(Misc.ascending(s => ExportPdf.$orderDraconic(s) + s.name))
for (let pos = 0; pos < sorts.length; pos++) {
const sort = sorts[pos]
this.$setFormSort(pos, sort)
}
}
$setFormSort(pos, sort) {
this.$setFormValue(`sorts.${pos}.name`, sort.name)
this.$setFormValue(`sorts.${pos}.voie`, sort.system.draconic)
this.$setFormValue(`sorts.${pos}.tmr`, sort.system.caseTMRSpeciale ?? sort.system.caseTMR)
this.$setFormValue(`sorts.${pos}.diff`, sort.system.difficulte)
this.$setFormValue(`sorts.${pos}.reve`, sort.system.ptreve)
this.$setFormValue(`sorts.${pos}.bonuscase`, sort.system.bonuscase)
}
static $orderDraconic(s) {
switch (s.system.draconic.substring(0, 1)) {
case 'O': return 1
case 'H': return 2
case 'N': return 3
case 'T': return 4
}
return 5
}
$setFormValue(path, value) {
const hasField = this.form.getFieldMaybe(path)
if (hasField && value != undefined) {
const field = this.form.getTextField(path)
field.setText(value.toString())
}
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -3,7 +3,7 @@ import { SYSTEM_RDD } from "../../constants.js";
import { Misc } from "../../misc.js";
import { EXPORT_CSV_SCRIPTARIUM, OptionsAvancees } from "../../settings/options-avancees.js";
import { ExportScriptarium } from "./export-scriptarium.js";
import { CATEGORIES_COMPETENCES, CATEGORIES_DRACONIC, Mapping } from "./mapping.js";
import { CATEGORIES_COMPETENCES_BASE, CATEGORIES_DRACONIC, Mapping } from "./mapping.js";
export class RdDActorExportSheet extends RdDActorSheet {
static init() {
@@ -44,7 +44,7 @@ export class RdDActorExportSheet extends RdDActorSheet {
formData.context = Mapping.prepareContext(this.actor)
formData.attaques = this.actor.listActionsAttaque()
formData.export = this.getMappingValues(formData.context, this.actor)
formData.competences = this.getCompetences(CATEGORIES_COMPETENCES)
formData.competences = this.getCompetences(CATEGORIES_COMPETENCES_BASE)
formData.draconic = this.getCompetences(CATEGORIES_DRACONIC)
const legeres = this.actor.nbBlessuresLegeres()
const graves = this.actor.nbBlessuresGraves()
+12 -12
View File
@@ -1,15 +1,15 @@
import { Grammar } from "../../grammar.js"
import { RdDItemArme } from "../../item/arme.js"
import { EMPOIGNADE, RdDItemArme } from "../../item/arme.js"
import { RdDItemCompetence } from "../../item-competence.js"
import { RdDItemSort } from "../../item-sort.js"
import { ITEM_TYPES } from "../../constants.js"
import { ITEM_TYPES, RDD_CONFIG } 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 = [
export const CATEGORIES_COMPETENCES_BASE = [
"generale",
"particuliere",
"specialisee",
@@ -88,7 +88,7 @@ const MAPPING_BASE = [
{ column: "endurance_actuel", rollClass: 'jet-endurance', getter: (actor, context) => actor.system.sante.endurance.value },
{ column: "esquive", getter: (actor, context) => Mapping.getEsquive(context) },
{ column: "esquive_armure", getter: (actor, context) => Mapping.getEsquiveArmure(context) },
{ column: "competences", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_COMPETENCES) },
{ column: "competences", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_COMPETENCES_BASE) },
{ column: "draconic", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_DRACONIC) },
]
@@ -141,7 +141,7 @@ export class Mapping {
static prepareArmes(actor) {
const armes = actor.items.filter(it => it.type == ITEM_TYPES.arme)
armes.push(RdDItemArme.corpsACorps(actor));
armes.push(RdDItemArme.pugilat(actor));
armes.push(RdDItemArme.empoignade(actor));
return armes.map(arme => [
arme.system.unemain ? Mapping.prepareArme(actor, arme, '(1 main)') : undefined,
@@ -160,7 +160,7 @@ export class Mapping {
return undefined
}
const categorie = Mapping.complementCategorie(arme, maniement)
const dommages = Mapping.dommagesArme(actor, arme, maniement)
const dommages = Mapping.dommages(actor, arme, maniement)
return {
name: arme.name + categorie,
niveau: Misc.toSignedString(competence.system.niveau),
@@ -170,12 +170,13 @@ export class Mapping {
arme: arme
}
}
static dommagesArme(actor, arme, maniement) {
static dommages(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 '-'
case RDD_CONFIG.encaissement.nonmortel: return `(${dommages})`
case RDD_CONFIG.encaissement.empoignade: return '-'
}
return dommages
}
@@ -274,11 +275,10 @@ export class Mapping {
}
static getDescription(actor) {
const sexe = actor.system.sexe
const sexeFeminin = sexe.length > 0 && sexe.charAt(0).toLowerCase() == 'f' ? 'Née' : 'Né'
const naissance = actor.isFeminin() ? '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 hn = `${naissance} à 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
+19 -11
View File
@@ -20,14 +20,15 @@ const PATHS = [
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 },
'system.cheveux': { 'noirs': 2, 'bruns': 5, 'châtains': 3, 'châtain clair': 5, 'blonds': 4, 'blond platine': 1, 'roux carotte': 1, 'roux cuivré': 3, 'chauve': 1 },
'system.yeux': { 'noirs': 2, 'noisette': 3, 'brun-vert': 4, 'verts': 3, 'bleu clair': 3, 'bleu gris': 2, 'gris': 1, 'mauves': 1, 'indigos': 1 },
}
export class AppPersonnageAleatoire extends FormApplication {
static preloadHandlebars() {
foundry.applications.handlebars.loadTemplates([
'systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/random/sexe-aleatoire.hbs',
])
}
@@ -49,14 +50,14 @@ export class AppPersonnageAleatoire extends FormApplication {
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
'system.sexe': (this.actor.system.sexe ?? '') == '',
'system.age': this.actor.system.age == 0,
'system.taille': (this.actor.system.taille ?? '') == '',
'system.poids': (this.actor.system.poids ?? '') == '',
'system.main': (this.actor.system.main ?? '') == '',
'system.heure': (this.actor.system.heure ?? '') == '',
'system.cheveux': (this.actor.system.cheveux ?? '') == '',
'system.yeux': (this.actor.system.yeux ?? '') == '',
}
}
@@ -76,6 +77,8 @@ export class AppPersonnageAleatoire extends FormApplication {
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[data-action="sexe-masculin"]').click(async event => await this.onSexe('masculin'))
this.html.find('a[data-action="sexe-feminin"]').click(async event => await this.onSexe('féminin'))
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())
@@ -96,6 +99,10 @@ export class AppPersonnageAleatoire extends FormApplication {
const fields = this.html.find(selector).parents("div.random-field:first")
return fields[0].attributes['data-path'].value
}
async onSexe(sexe) {
this.current['system.sexe'] = sexe
this.render()
}
async onChange(event) {
const path = this.getPath(event.currentTarget)
@@ -180,8 +187,9 @@ export class AppPersonnageAleatoire extends FormApplication {
const variation = Math.floor((caracTaille.poidsMax - caracTaille.poidsMin + base / 5) / 2)
const total = await RdDDice.rollTotal(`2d${variation} + ${base}`)
const cm = total % 100
const dm = cm < 10 ? '0' : ''
const m = (total - cm) / 100
return `${m}m${cm}`
return `${m}m${dm}${cm}`
}
@@ -1,3 +1,4 @@
import { renderTemplate } from "../../constants.js";
export class TextRollManager {
+27 -4
View File
@@ -1,5 +1,5 @@
import { Misc } from "./misc.js";
import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { renderTemplate, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
@@ -106,6 +106,25 @@ export class ChatUtility {
return await ChatMessage.create(messageData)
}
static tellToUser(message) {
ChatMessage.create({ content: message, user: game.user.id, whisper: [game.user.id] });
}
static tellToGM(message) {
ChatMessage.create({
user: game.user.id,
content: message,
whisper: ChatUtility.getGMs()
});
}
static tellToUserAndGM(message) {
ChatMessage.create({
user: game.user.id,
content: message,
whisper: ChatUtility.getUserAndGMs()
})
}
static getOwners(document) {
return document ? game.users.filter(it => document.getUserLevel(it) == CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) : [game.user]
}
@@ -190,15 +209,19 @@ export class ChatUtility {
if (rddTimestamp) {
const timestamp = new RdDTimestamp(rddTimestamp);
const timestampData = timestamp.toCalendrier();
const dateHeure = await foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/common/date-heure.hbs', timestampData);
$(html).find('header.message-header .message-sender').after(dateHeure)
const dateHeure = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/common/date-heure.hbs', timestampData);
$(html).find('header.message-header .message-timestamp').after(dateHeure)
}
}
static async onCreateChatMessage(chatMessage, options, id) {
if (chatMessage.isAuthor) {
await chatMessage.setFlag(SYSTEM_RDD, 'rdd-timestamp', game.system.rdd.calendrier.getTimestamp());
await ChatUtility.setTimestamp(chatMessage)
await chatMessage.update({ content: await RdDTextEditor.enrichHTML(chatMessage.content, undefined, { showLink: false }) })
}
}
static async setTimestamp(chatMessage) {
await chatMessage.setFlag(SYSTEM_RDD, 'rdd-timestamp', game.system.rdd.calendrier.getTimestamp());
}
}
+1
View File
@@ -1,5 +1,6 @@
import { RdDBaseActor } from "../actor/base-actor.js";
import { ChatUtility } from "../chat-utility.js";
import { renderTemplate } from "../constants.js";
const INFO_COEUR = 'info-coeur';
+57 -33
View File
@@ -9,47 +9,70 @@ export const ENTITE_INCARNE = 'incarne'
export const ENTITE_NONINCARNE = 'nonincarne'
export const ENTITE_BLURETTE = 'blurette'
export const renderTemplate = foundry.applications.handlebars.renderTemplate
export const RDD_CONFIG = {
niveauEthylisme : [
{value: "1", label: "Aucun"},
{value: "0", label: "Eméché (0)"},
{value: "-1", label: "Gris (-1)"},
{value: "-2", label: "Pinté (-2)"},
{value: "-3", label: "Pas Frais (-3)"},
{value: "-4", label: "Ivre (-4)"},
{value: "-5", label: "Bu (-5)"},
{value: "-6", label: "Complètement fait (-6)"},
{value: "-7", label: "Ivre mort (-7)"}
niveauEthylisme: [
{ value: '1', label: 'Aucun' },
{ value: '0', label: 'Eméché (0)' },
{ value: '-1', label: 'Gris (-1)' },
{ value: '-2', label: 'Pinté (-2)' },
{ value: '-3', label: 'Pas Frais (-3)' },
{ value: '-4', label: 'Ivre (-4)' },
{ value: '-5', label: 'Bu (-5)' },
{ value: '-6', label: 'Complètement fait (-6)' },
{ value: '-7', label: 'Ivre mort (-7)' }
],
categorieEntite: {
"cauchemar": "Cauchemar",
"reve": "Rêve"
'cauchemar': 'Cauchemar',
'reve': 'Rêve'
},
typeEntite: {
"incarne": "Incarnée",
"nonincarne": "Non Incarnée",
"blurette": "Blurette"
[ENTITE_INCARNE]: 'Incarnée',
[ENTITE_NONINCARNE]: 'Non Incarnée',
[ENTITE_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"}
heuresRdD: [
{ value: 'vaisseau', label: 'Vaisseau', img: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd01.webp' },
{ value: 'sirene', label: 'Sirène', img: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd02.webp' },
{ value: 'faucon', label: 'Faucon', img: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd03.webp' },
{ value: 'couronne', label: 'Couronne', img: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd04.webp' },
{ value: 'dragon', label: 'Dragon', img: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd05.webp' },
{ value: 'epees', label: 'Epées', img: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd06.webp' },
{ value: 'lyre', label: 'Lyre', img: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd07.webp' },
{ value: 'serpent', label: 'Serpent', img: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd08.webp' },
{ value: 'poissonacrobate', label: 'Poisson Acrobate', img: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd09.webp' },
{ value: 'araignee', label: 'Araignée', img: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd10.webp' },
{ value: 'roseau', label: 'Roseau', img: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd11.webp' },
{ value: 'chateaudormant', label: 'Chateau Dormant', img: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd12.webp' }
],
raretes: [
{value: "Commune", label: "Commune"},
{value: "Frequente", label: "Fréquente"},
{value: "Rare", label: "Rare"},
{value: "Rarissime", label: "Rarissime"}
]
{ value: 'Commune', label: 'Commune' },
{ value: 'Frequente', label: 'Fréquente' },
{ value: 'Rare', label: 'Rare' },
{ value: 'Rarissime', label: 'Rarissime' }
],
particuliere: {
force: { key: 'force', descr: 'en force', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-force.svg' },
finesse: { key: 'finesse', descr: 'en finesse', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-finesse.svg' },
rapidite: { key: 'rapidite', descr: 'en rapidité', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-rapidite.svg' },
},
icons: {
armesDisparates: 'systems/foundryvtt-reve-de-dragon/assets/actions/armes-disparates.svg',
demiReve: 'systems/foundryvtt-reve-de-dragon/assets/actions/sort.svg',
empoignade: 'systems/foundryvtt-reve-de-dragon/assets/actions/empoignade.svg',
forceWeak: 'systems/foundryvtt-reve-de-dragon/assets/actions/weak.svg',
surenc: 'systems/foundryvtt-reve-de-dragon/assets/actions/surenc.svg',
magique: 'systems/foundryvtt-reve-de-dragon/assets/actions/magique.svg',
armebrisee: 'systems/foundryvtt-reve-de-dragon/assets/actions/arme-brisee.svg',
malade: 'systems/foundryvtt-reve-de-dragon/assets/actions/malade.svg',
},
encaissement: {
mortel: 'mortel',
nonmortel: 'non-mortel',
entiteincarnee: 'entiteincarnee',
empoignade: 'empoignade'
}
}
export const ACTOR_TYPES = {
@@ -106,3 +129,4 @@ export const ITEM_TYPES = {
nombreastral: 'nombreastral',
extraitpoetique: 'extraitpoetique',
}
+1
View File
@@ -1,3 +1,4 @@
import { renderTemplate } from "./constants.js"
export class DialogChoixXpCarac extends Dialog {
+1 -1
View File
@@ -1,4 +1,4 @@
import { SYSTEM_RDD } from "./constants.js";
import { renderTemplate, SYSTEM_RDD } from "./constants.js";
import { Grammar } from "./grammar.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
+1
View File
@@ -1,4 +1,5 @@
import { ChatUtility } from "./chat-utility.js";
import { renderTemplate } from "./constants.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDItemSigneDraconique } from "./item/signedraconique.js";
import { TMRUtility } from "./tmr-utility.js";
+1
View File
@@ -1,3 +1,4 @@
import { renderTemplate } from "./constants.js";
import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js";
+1
View File
@@ -1,3 +1,4 @@
import { renderTemplate } from "./constants.js";
import { Misc } from "./misc.js";
export class DialogConsommer extends Dialog {
+1
View File
@@ -1,3 +1,4 @@
import { renderTemplate } from "./constants.js"
export class DialogSelect extends Dialog {
static extractIdNameImg(it) { return { id: it.id, name: it.name, img: it.img } }
+1 -1
View File
@@ -1,4 +1,4 @@
import { Misc } from "./misc.js";
import { renderTemplate } from "./constants.js";
export class DialogSplitItem extends Dialog {
+12 -13
View File
@@ -1,4 +1,4 @@
import { HIDE_DICE, SHOW_DICE } from "./constants.js";
import { HIDE_DICE, renderTemplate, SHOW_DICE } from "./constants.js";
import { RdDUtility } from "./rdd-utility.js";
/**
@@ -7,18 +7,17 @@ import { RdDUtility } from "./rdd-utility.js";
*/
export class DialogValidationEncaissement extends Dialog {
static async validerEncaissement(actor, rollData, armure, onEncaisser) {
const encaissement = await RdDUtility.jetEncaissement(actor, rollData, armure, { showDice: HIDE_DICE });
static async validerEncaissement(actor, dmg, armure, onEncaisser) {
const encaissement = await RdDUtility.jetEncaissement(actor, dmg, armure, { showDice: HIDE_DICE });
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-validation-encaissement.hbs', {
actor: actor,
rollData: rollData,
encaissement: encaissement
});
new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, onEncaisser).render(true);
new DialogValidationEncaissement(html, actor, dmg, armure, encaissement, onEncaisser).render(true);
}
/* -------------------------------------------- */
constructor(html, actor, rollData, armure, encaissement, onEncaisser) {
constructor(html, actor, dmg, armure, encaissement, onEncaisser) {
// Common conf
let buttons = {
"valider": { label: "Valider", callback: html => this.onValider() },
@@ -42,11 +41,11 @@ export class DialogValidationEncaissement extends Dialog {
super(dialogConf, dialogOptions);
this.actor = actor
this.rollData = rollData;
this.armure = armure;
this.encaissement = encaissement;
this.onEncaisser = onEncaisser;
this.forceDiceResult = {total: encaissement.roll.result };
this.dmg = dmg
this.armure = armure
this.encaissement = encaissement
this.onEncaisser = onEncaisser
this.forceDiceResult = {total: encaissement.roll.result }
}
/* -------------------------------------------- */
@@ -55,14 +54,14 @@ export class DialogValidationEncaissement extends Dialog {
this.html = html;
this.html.find('input.encaissement-roll-result').keyup(async event => {
this.forceDiceResult.total = event.currentTarget.value;
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.dmg, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
this.html.find('label.encaissement-total').text(this.encaissement.total);
this.html.find('label.encaissement-blessure').text(this.encaissement.blessures)
});
}
async onValider() {
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.dmg, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
this.onEncaisser(this.encaissement)
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
import { ITEM_TYPES } from "../constants.js"
import { ITEM_TYPES, renderTemplate } from "../constants.js"
import { RdDItemSort } from "../item-sort.js"
import { Misc } from "../misc.js"
+62 -3
View File
@@ -1,7 +1,66 @@
export const MAP_PHASE = {
possession: { label: "possession", rang: 10 },
draconic: { label: "draconic", rang: 9 },
tir: { label: "tir", rang: 8 },
lancer: { label: "lancer", rang: 7 },
arme: { label: "mêlée", rang: 5 },
pugilat: { label: "pugilat", rang: 4 },
naturelle: { label: "créature", rang: 4 },
empoignade: { label: "empoignade", rang: 3 },
autre: { label: "autre action", rang: 2 },
demi: { label: "demi-surprise", rang: 0 },
totale: { label: "surprise totale", rang: -1 },
}
export const PHASE = Object.values(MAP_PHASE)
export class RdDInitiative {
static calculInitiative(niveau, caracValue, bonus = 0) {
let base = niveau + Math.floor(caracValue / 2) + bonus;
return "1d6" + (base >= 0 ? "+" : "") + base;
static getRollInitiative(caracValue, niveau, bonus = 0) {
const base = RdDInitiative.ajustementInitiative(caracValue, niveau, bonus)
return "1d6" + (base >= 0 ? "+" : "") + base
}
static ajustementInitiative(caracValue, niveau, bonus = 0) {
return niveau + Math.floor(caracValue / 2) + bonus
}
static formule(phase, carac, niveau, bonusMalus = 0) {
const ajustement = RdDInitiative.ajustementInitiative(carac, niveau, bonusMalus)
return { phase, ajustement }
}
static phaseArme(categorie, arme) {
switch (categorie) {
case "tir":
case "lancer":
return MAP_PHASE[categorie]
default:
switch (arme.system.cac) {
case "empoignade":
case "pugilat":
case "naturelle":
return MAP_PHASE[arme.system.cac]
default:
return MAP_PHASE['arme']
}
}
}
static phase(keyOrRang) {
return MAP_PHASE[keyOrRang] ?? PHASE.find(it => it.rang == keyOrRang) ?? MAP_PHASE.autre
}
static async roll(formule) {
const sign = formule.ajustement >= 0 ? "+" : ""
const roll = new Roll(`1d6 + ${sign} + ${formule.ajustement}`)
await roll.evaluate()
const value = Math.max(roll.total, 0)
return {
roll: roll,
value: value,
rang: formule.phase.rang,
init: formule.phase.rang + value / 100,
label: formule.phase.label
}
}
}
+33 -12
View File
@@ -1,6 +1,8 @@
import { Grammar } from "./grammar.js";
import { RdDInitiative } from "./initiative.mjs";
import { RdDItem } from "./item.js";
import { SANS_COMPETENCE } from "./item/base-items.js";
import { CATEGORIES_COMPETENCE_COMBAT, CATEGORIES_COMPETENCES, SANS_COMPETENCE } from "./item/base-items.js";
import { Misc } from "./misc.js";
const competenceTroncs = [["Esquive", "Dague", "Corps à corps"],
@@ -25,16 +27,6 @@ const limitesArchetypes = [
];
/* -------------------------------------------- */
export const CATEGORIES_COMPETENCES = {
"generale": { base: -4, label: "Générales" },
"particuliere": { base: -8, label: "Particulières" },
"specialisee": { base: -11, label: "Spécialisées" },
"connaissance": { base: -11, label: "Connaissances" },
"draconic": { base: -11, label: "Draconic" },
"melee": { base: -6, label: "Mêlée" },
"tir": { base: -8, label: "Tir" },
"lancer": { base: -8, label: "Lancer" }
}
function _buildCumulXP() {
let cumulXP = { "-11": 0 };
@@ -49,7 +41,36 @@ function _buildCumulXP() {
const competence_xp_cumul = _buildCumulXP();
export class RdDItemCompetence extends Item {
export class RdDItemCompetence extends RdDItem {
static get ITEM_TYPE() { return ITEM_TYPES.competence }
static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp" }
isNiveauBase() {
return this.system.niveau == this.system.base && this.system.xp == 0
}
getBaseInit() {
const carac = this.getInitCarac()
if (carac == undefined) {
return undefined
}
return RdDInitiative.ajustementInitiative(carac.value, this.system.niveau)
}
getInitCarac() {
if (!this.actor) {
return undefined
}
switch (this.system.categorie) {
case CATEGORIES_COMPETENCES.melee.key: return this.actor.system.carac.melee
case CATEGORIES_COMPETENCES.tir.key: return this.actor.system.carac.tir
case CATEGORIES_COMPETENCES.lancer.key: return this.actor.system.carac.lancer
case CATEGORIES_COMPETENCES.draconic.key: return this.actor.system.carac.reve
}
return undefined
}
/* -------------------------------------------- */
static getLabelCategorie(category) {
return CATEGORIES_COMPETENCES[category].label;
+45 -95
View File
@@ -1,126 +1,76 @@
import { ITEM_TYPES } from "./constants.js";
import { Grammar } from "./grammar.js";
import { RdDInitiative } from "./initiative.mjs";
import { RdDItem } from "./item.js";
export const CATEGORIES_COMPETENCES_CREATURES = {
"generale": { base: 0, label: "Générale" },
"naturelle": { base: 0, label: "Arme naturelle" },
"melee": { base: 0, label: "Mêlée" },
"parade": { base: 0, label: "Parade" },
"tir": { base: 0, label: "Tir" },
"lancer": { base: 0, label: "Lancer" },
"possession": { base: 0, label: "Possession" },
}
import { RdDInitiative } from "./initiative.mjs";
import { RdDItemArme } from "./item/arme.js";
/* -------------------------------------------- */
export class RdDItemCompetenceCreature extends Item {
export class RdDItemCompetenceCreature extends RdDItem {
/* -------------------------------------------- */
static setRollDataCreature(rollData) {
const code = Grammar.toLowerCaseNoAccentNoSpace(rollData.competence.name);
const selectedCarac = { code: code, label: rollData.competence.name, value: rollData.competence.system.carac_value };
rollData.carac = { [code]: selectedCarac }
rollData.competence.system.defaut_carac = code
rollData.selectedCarac = selectedCarac
rollData.arme = RdDItemCompetenceCreature.armeCreature(rollData.competence);
}
static get ITEM_TYPE() { return ITEM_TYPES.competencecreature }
/* -------------------------------------------- */
static armeCreature(item) {
const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(item)
static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp" }
isAttaque() { return this.getCategorieAttaque() != undefined }
isParade() { return this.system.iscombat && (this.system.categorie_parade ?? '') != '' }
isBouclier() { return this.system.categorie_parade.includes('bouclier') }
attaqueCreature() {
const categorieAttaque = this.getCategorieAttaque()
if (categorieAttaque != undefined) {
// cloner pour ne pas modifier la compétence
return foundry.utils.mergeObject(item, {
action: item.isCompetencePossession() ? 'possession' : 'attaque',
system: {
competence: item.name,
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
niveau: item.system.niveau,
initiative: RdDInitiative.calculInitiative(item.system.niveau, item.system.carac_value),
equipe: true,
resistance: 100,
dommagesReels: item.system.dommages,
penetration: 0,
force: 0,
rapide: true,
}
}, { inplace: false, });
}
return undefined;
}
static attaqueCreature(comp) {
const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(comp)
if (categorieAttaque != undefined) {
const initative = RdDInitiative.calculInitiative(comp.system.niveau, comp.system.carac_value);
return {
name: comp.name,
action: comp.isCompetencePossession() ? 'possession' : 'attaque',
const initative = RdDInitiative.getRollInitiative(this.system.carac_value, this.system.niveau);
const attaque = {
label: this.name,
action: this.isCompetencePossession() ? 'possession' : 'attaque',
initOnly: false,
arme: new RdDItem({
name: comp.name,
arme: new RdDItemArme({
name: this.name,
type: ITEM_TYPES.arme,
img: comp.img,
img: this.img,
system: {
competence: comp.name,
competence: this.name,
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
niveau: comp.system.niveau,
niveau: this.system.niveau,
initiative: initative,
mortalite: this.system.mortalite,
dommages: this.system.dommages,
forceRequise: 0,
equipe: true,
resistance: 100,
dommagesReels: comp.system.dommages,
penetration: 0,
force: 0,
rapide: true,
}
}),
comp: comp,
// main: '',
carac: { key: comp.name, value: comp.system.carac_value },
comp: this,
carac: { key: this.name, value: this.system.carac_value },
equipe: true,
dmg: comp.system.dommages,
mortalite: this.system.mortalite,
dommages: this.system.dommages,
//dmg: this.system.dommages,
initiative: initative
}
};
return attaque
}
return undefined;
}
/* -------------------------------------------- */
static isAttaque(item) {
return RdDItemCompetenceCreature.getCategorieAttaque(item) != undefined
}
static getCategorieAttaque(item) {
if (item.type == ITEM_TYPES.competencecreature) {
switch (item.system.categorie) {
case "melee":
case "tir":
case "lancer":
case "naturelle":
case "possession":
return item.system.categorie
}
getCategorieAttaque() {
switch (this.system.categorie) {
case "melee":
case "tir":
case "lancer":
case "naturelle":
case "possession":
return this.system.categorie
}
return undefined
}
static isDommages(item) {
if (item.type == ITEM_TYPES.competencecreature) {
switch (item.system.categorie) {
case "melee":
case "tir":
case "lancer":
case "naturelle":
return true
}
}
return false
}
static isParade(item) {
if (item.type == ITEM_TYPES.competencecreature) {
return item.system.categorie_parade || item.system.isparade
isDommages() {
switch (this.system.categorie) {
case "melee":
case "tir":
case "lancer":
case "naturelle":
return true
}
return false
}
+7 -8
View File
@@ -1,7 +1,9 @@
import { ACTOR_TYPES, ITEM_TYPES } from "./constants.js";
import { RdDItem } from "./item.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemSort } from "./item-sort.js";
import { RdDUtility } from "./rdd-utility.js";
import { RdDItemCompetence } from "./item-competence.js";
import { HtmlUtility } from "./html-utility.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { SYSTEM_RDD } from "./constants.js";
@@ -9,8 +11,6 @@ import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { Misc } from "./misc.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { RdDItem } from "./item.js";
import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js";
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
import { ItemAction } from "./item/item-actions.js";
@@ -106,8 +106,8 @@ export class RdDItemSheetV1 extends foundry.appv1.sheets.ItemSheet {
}
if (this.item.type == ITEM_TYPES.competencecreature) {
formData.isparade = RdDItemCompetenceCreature.isParade(this.item)
formData.isdommages = RdDItemCompetenceCreature.isDommages(this.item)
formData.isparade = this.item.isParade()
formData.isdommages = this.item.isDommages()
}
if (this.item.type == ITEM_TYPES.tache ||
this.item.type == ITEM_TYPES.livre ||
@@ -260,7 +260,7 @@ export class RdDItemSheetV1 extends foundry.appv1.sheets.ItemSheet {
/* -------------------------------------------- */
/** @override */
_updateObject(event, formData) {
async _updateObject(event, formData) {
switch (this.item.type) {
case ITEM_TYPES.sort:
formData['system.bonuscase'] = RdDItemSort.bonuscasesToString(RdDItemSheetV1._listCaseTmr(
@@ -273,8 +273,7 @@ export class RdDItemSheetV1 extends foundry.appv1.sheets.ItemSheet {
formData['system.niveau'] = formData['system.niveau'] ?? formData['system.base']
break
}
return this.item.update(formData)
return await super._updateObject(event, formData)
}
/* -------------------------------------------- */
+29 -6
View File
@@ -62,7 +62,7 @@ export class RdDItemSort extends Item {
static diffReve(sort) { return RdDItemSort.toVar((sort.system.difficulte.match(/\-?(\d)+/) ? 'R' : 'R ') + sort.system.difficulte) }
static coutReve(sort) { return RdDItemSort.toVar((sort.system.ptreve.match(/(\d)+\+?/) ? 'r' : 'r ') + sort.system.ptreve) }
static coutReve(sort) { return RdDItemSort.toVar((Number.isInteger(sort.system.ptreve || sort.system.ptreve.match(/(\d)+\+?/)) ? 'r' : 'r ') + sort.system.ptreve) }
static getDraconicsSort(competencesDraconic, sort) {
// se baser sur la voie du sort?
switch (Grammar.toLowerCaseNoAccent(sort.name)) {
@@ -148,10 +148,17 @@ export class RdDItemSort extends Item {
/* -------------------------------------------- */
static incrementBonusCase(actor, sort, coord) {
let bonuscase = RdDItemSort.calculBonuscase(sort, coord)
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': bonuscase }]);
}
static calculBonuscase(sort, coord) {
if (TMRUtility.isFleuve(coord)) {
coord = FLEUVE_COORD;
coord = FLEUVE_COORD
}
let list = RdDItemSort.stringToBonuscases(sort.system.bonuscase);
let list = RdDItemSort.stringToBonuscases(sort.system.bonuscase)
const existing = list.find(it => it.case == coord)
const bonus = Number(existing?.bonus ?? 0) + 1
if (existing) {
@@ -160,11 +167,9 @@ export class RdDItemSort extends Item {
else {
list.push({ case: coord, bonus: 1 })
}
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': RdDItemSort.bonuscasesToString(list) }]);
return RdDItemSort.bonuscasesToString(list)
}
/* -------------------------------------------- */
static getCaseBonus(sort, coord) {
const search = TMRUtility.isFleuve(coord)
@@ -189,4 +194,22 @@ export class RdDItemSort extends Item {
.map(it => it.split(':'))
.map(it => { return { case: it[0], bonus: it[1] } });
}
static prepareSortEnReserve(sort, draconic, ptreve, coord) {
return {
type: ITEM_TYPES.sortreserve,
name: sort.name,
img: sort.img,
system: { sortid: sort._id, draconic: (draconic?.name ?? sort.system.draconic), ptreve: ptreve, coord: coord, heurecible: 'Vaisseau' }
};
}
static prepareSortAddLancement(sort, reveSort) {
const precedents = sort.system.lancements ?? []
const lancements = [...precedents, {
timestamp: game.system.rdd.calendrier.getTimestamp(),
reve: reveSort
}]
return lancements
}
}
+8 -7
View File
@@ -1,4 +1,6 @@
import { ITEM_TYPES } from "./constants.js";
import { ITEM_TYPES, RDD_CONFIG, renderTemplate } from "./constants.js";
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, CATEGORIES_COMPETENCES, CATEGORIES_COMPETENCES_CREATURES } from "./item/base-items.js";
import { ITEM_ACTIONS, DEFAULT_ACTIONS, COMMON_ACTIONS } from "./item/item-actions.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
@@ -7,10 +9,6 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDUtility } from "./rdd-utility.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { RdDRaretes } from "./item/raretes.js";
import { CATEGORIES_COMPETENCES } from "./item-competence.js";
import { CATEGORIES_COMPETENCES_CREATURES } from "./item-competencecreature.js";
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE } from "./item/base-items.js";
import { ITEM_ACTIONS, DEFAULT_ACTIONS, COMMON_ACTIONS } from "./item/item-actions.js";
const typesInventaireMateriel = [
ITEM_TYPES.arme,
@@ -186,7 +184,10 @@ export class RdDItem extends Item {
isMonnaie() { return this.type == ITEM_TYPES.monnaie; }
isNourritureBoisson() { return this.type == ITEM_TYPES.nourritureboisson; }
isService() { return this.type == ITEM_TYPES.service; }
isAttaque() { return false }
isParade() { return false }
isBouclier() { return false }
getCategorieAttaque() { return undefined }
isCompetence() { return typesObjetsCompetence.includes(this.type) }
isEsquive() {
return (this.isCompetence()
@@ -628,7 +629,7 @@ export class RdDItem extends Item {
_armeChatData() {
return [
`<b>Compétence</b>: ${this.system.competence}`,
`<b>Dommages</b>: ${this.system.dommages} ${this.system.mortalite == 'non-mortel' ? '(Non mortel)' : ''}`,
`<b>Dommages</b>: ${this.system.dommages} ${this.system.mortalite == RDD_CONFIG.encaissement.nonmortel ? '(Non mortel)' : ''}`,
`<b>Force minimum</b>: ${this.system.force}`,
`<b>Resistance</b>: ${this.system.resistance}`,
...this._inventaireTemplateChatData()
+95 -60
View File
@@ -1,10 +1,10 @@
import { ITEM_TYPES } from "../constants.js";
import { ITEM_TYPES, RDD_CONFIG } from "../constants.js";
import { RdDItem } from "../item.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js"
import { BASE_CORPS_A_CORPS } from "./base-items.js";
import { Grammar } from "../grammar.js";
import { RdDInitiative } from "../initiative.mjs";
import { MappingCreatureArme } from "./mapping-creature-arme.mjs";
import { Misc } from "../misc.js";
const nomCategorieParade = {
"sans-armes": "Sans arme",
@@ -19,26 +19,67 @@ const nomCategorieParade = {
"haches": "Haches",
"lances": "Lances",
}
export const ATTAQUE_TYPE = {
UNE_MAIN: '(1 main)',
DEUX_MAINS: '(2 mains)',
CORPS_A_CORPS: '(corps à corps)',
COMPETENCE: 'competence',
TIR: '(tir)',
LANCER: '(lancer)'
}
export const ATTAQUE_TYPE_MELEE = [ATTAQUE_TYPE.UNE_MAIN, ATTAQUE_TYPE.DEUX_MAINS, ATTAQUE_TYPE.CORPS_A_CORPS]
export const CORPS_A_CORPS = 'Corps à corps'
export const PUGILAT = 'pugilat'
export const EMPOIGNADE = RDD_CONFIG.encaissement.empoignade
/* -------------------------------------------- */
export class RdDItemArme extends RdDItem {
static get ITEM_TYPE() { return ITEM_TYPES.arme }
static get defaultIcon() {
return defaultItemImgArme
//return "systems/foundryvtt-reve-de-dragon/icons/armes_armure/epee_sord.webp";
static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/armes_armures/epee_gnome.webp" }
penetration() { return parseInt(this.system.penetration ?? 0) }
isParade() { return this.system.resistance > 0 && this.system.categorie_parade }
isBouclier() { return RdDItemArme.getCategorieParade(this).includes('bouclier') }
getCompetenceAction(main) {
switch (main) {
case ATTAQUE_TYPE.UNE_MAIN: return this.competence1Mains()
case ATTAQUE_TYPE.DEUX_MAINS: return this.competence2Mains()
case ATTAQUE_TYPE.LANCER: return this.system.lancer
case ATTAQUE_TYPE.TIR: return this.system.tir
default: return this.system.competence
}
}
/* -------------------------------------------- */
static valeurMain(valeurs, main) {
valeurs = valeurs?.toString() ?? ""
const table = valeurs.includes("/") ? valeurs.split("/") : [valeurs, valeurs]
return parseInt(main == ATTAQUE_TYPE.DEUX_MAINS ? table[1] : table[0])
}
/* -------------------------------------------- */
static getMainAttaque(competence) {
switch (competence.system.categorie) {
case 'tir': return ATTAQUE_TYPE.TIR
case 'lancer': return ATTAQUE_TYPE.LANCER
}
if (competence.name.includes('2 main')) {
return ATTAQUE_TYPE.DEUX_MAINS
}
return ATTAQUE_TYPE.UNE_MAIN
}
static getArme(arme) {
switch (arme ? arme.type : '') {
case ITEM_TYPES.arme: return arme;
case ITEM_TYPES.competencecreature:
return RdDItemCompetenceCreature.armeCreature(arme);
return MappingCreatureArme.armeCreature(arme);
}
return RdDItemArme.corpsACorps();
return RdDItemArme.pugilat();
}
static getCompetenceArme(arme, maniement) {
@@ -47,16 +88,26 @@ export class RdDItemArme extends RdDItem {
return arme.name
case ITEM_TYPES.arme:
switch (maniement) {
case 'competence': return arme.system.competence;
case '(1 main)': return arme.competence1Mains()
case '(2 mains)': return arme.competence2Mains()
case '(tir)': case 'tir': return arme.system.tir
case '(lancer)': case 'lancer': return arme.system.lancer;
case ATTAQUE_TYPE.COMPETENCE: return arme.system.competence
case ATTAQUE_TYPE.UNE_MAIN: return arme.competence1Mains()
case ATTAQUE_TYPE.DEUX_MAINS: return arme.competence2Mains()
case ATTAQUE_TYPE.TIR: case 'tir': return arme.system.tir
case ATTAQUE_TYPE.LANCER: case 'lancer': return arme.system.lancer
case ATTAQUE_TYPE.CORPS_A_CORPS: return CORPS_A_CORPS
}
}
return undefined
}
getTypeAttaques() {
return [
...(this.system.unemain && this.system.competence && this.system.resistance > 0) ? [ATTAQUE_TYPE.UNE_MAIN] : [],
...(this.system.deuxmains && this.system.competence && this.system.resistance > 0) ? [ATTAQUE_TYPE.DEUX_MAINS] : [],
...(this.system.lancer && this.system.resistance > 0) ? [ATTAQUE_TYPE.LANCER] : [],
...(this.system.tir) ? [ATTAQUE_TYPE.TIR] : [],
]
}
static computeNiveauArmes(armes, competences) {
for (const arme of armes) {
arme.system.niveau = RdDItemArme.niveauCompetenceArme(arme, competences);
@@ -88,16 +139,13 @@ export class RdDItemArme extends RdDItem {
/* -------------------------------------------- */
static getCategorieParade(armeData) {
if (![ITEM_TYPES.arme, ITEM_TYPES.competencecreature].includes(armeData.type)) {
return ''
}
if (armeData.system.categorie_parade) {
return armeData.system.categorie_parade
}
// pour compatibilité avec des personnages existants
if (armeData.type == ITEM_TYPES.competencecreature || armeData.system.categorie == 'creature') {
return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : '')
}
if (!armeData.type.match(/arme|competencecreature/)) {
return ''
}
if (armeData.system.competence == undefined) {
return ITEM_TYPES.competencecreature;
}
@@ -192,7 +240,7 @@ export class RdDItemArme extends RdDItem {
return Number(arme.system.dommages)
}
const tableauDegats = arme.system.dommages.split("/");
return Number(tableauDegats[maniement == '(1 main)' ? 0 : 1])
return Number(tableauDegats[maniement == ATTAQUE_TYPE.UNE_MAIN ? 0 : 1])
}
return Number(arme.system.dommages);
}
@@ -201,7 +249,7 @@ export class RdDItemArme extends RdDItem {
static armeUneOuDeuxMains(arme, aUneMain) {
if (arme && !arme.system.cac) {
arme = foundry.utils.duplicate(arme);
arme.system.dommagesReels = RdDItemArme.dommagesReels(arme, aUneMain ? '(1 main)' : '(2 mains)')
arme.system.dommagesReels = RdDItemArme.dommagesReels(arme, aUneMain ? ATTAQUE_TYPE.UNE_MAIN : ATTAQUE_TYPE.DEUX_MAINS)
}
return arme;
}
@@ -222,63 +270,50 @@ export class RdDItemArme extends RdDItem {
return false
}
static isAttaque(arme) {
switch (arme.type) {
case ITEM_TYPES.arme: return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0)
case ITEM_TYPES.competencecreature: return arme.system.iscombat && RdDItemCompetenceCreature.isAttaque(item)
}
return false
isAttaque() {
return this.system.resistance > 0 || (this.system.tir != '' && this.system.portee_courte > 0)
}
static isParade(arme) {
switch (arme.type) {
case ITEM_TYPES.arme:
return arme.system.resistance > 0 && true/* TODO: regarder la categorie d'arme?*/
case ITEM_TYPES.competencecreature:
return arme.system.iscombat && RdDItemCompetenceCreature.isParade(arme)
}
return false
isEmpoignade() {
return this.system.mortalite == RDD_CONFIG.encaissement.empoignade
}
isUtilisableEmpoigne() {
return this.system.baseInit == 3 || this.system.baseInit == 4 || this.system.competence == "Dague"
}
static corpsACorps(actor) {
let competence = actor?.getCompetenceCorpsACorps() ?? BASE_CORPS_A_CORPS
let melee = actor ? actor.system.carac['melee'].value : 0
static pugilat(actor) {
return RdDItemArme.$corpsACorps(actor, 'Pugilat', PUGILAT)
}
static empoignade(actor) {
return RdDItemArme.$corpsACorps(actor, 'Empoignade', RDD_CONFIG.encaissement.empoignade)
}
static $corpsACorps(actor, name, cac) {
const competence = actor?.getCompetenceCorpsACorps() ?? BASE_CORPS_A_CORPS
const melee = actor ? actor.system.carac['melee'].value : 0
return new RdDItemArme({
_id: competence.id,
name: 'Corps à corps',
_id: Misc.fakeId(cac),
name: name,
type: ITEM_TYPES.arme,
img: competence.img,
system: {
initiative: RdDInitiative.calculInitiative(competence.system.niveau, melee),
initiative: RdDInitiative.getRollInitiative(melee, competence.system.niveau),
equipe: true,
rapide: true,
force: 0,
dommages: "0",
dommagesReels: 0,
mortalite: 'non-mortel',
competence: 'Corps à corps',
mortalite: cac == RDD_CONFIG.encaissement.empoignade ? RDD_CONFIG.encaissement.empoignade : RDD_CONFIG.encaissement.nonmortel,
competence: CORPS_A_CORPS,
resistance: 1,
baseInit: 4,
cac: 'pugilat',
baseInit: cac == RDD_CONFIG.encaissement.empoignade ? 3 : 4,
cac: cac,
deuxmains: true,
categorie_parade: 'sans-armes'
}
})
}
static mainsNues(actor) {
const mainsNues = RdDItemArme.corpsACorps(actor)
mainsNues.name = 'Mains nues'
return mainsNues;
}
static empoignade(actor) {
const empoignade = RdDItemArme.corpsACorps(actor)
empoignade.name = 'Empoignade'
empoignade.system.cac = 'empoignade'
empoignade.system.baseInit = 3
empoignade.system.mortalite = 'empoignade'
return empoignade
}
}
+23 -2
View File
@@ -14,7 +14,28 @@ export const SANS_COMPETENCE = {
description: "",
descriptionmj: "",
defaut_carac: "",
},
},
img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp"
}
}
export const CATEGORIES_COMPETENCES = {
generale: { key: 'generale', base: -4, label: "Générales" },
particuliere: { key: 'particuliere', base: -8, label: "Particulières" },
specialisee: { key: 'specialisee', base: -11, label: "Spécialisées" },
connaissance: { key: 'connaissance', base: -11, label: "Connaissances" },
draconic: { key: 'draconic', base: -11, label: "Draconic" },
melee: { key: 'melee', base: -6, label: "Mêlée" },
tir: { key: 'tir', base: -8, label: "Tir" },
lancer: { key: 'lancer', base: -8, label: "Lancer" }
}
export const CATEGORIES_COMPETENCE_COMBAT = [CATEGORIES_COMPETENCES.melee, CATEGORIES_COMPETENCES.tir, CATEGORIES_COMPETENCES.lancer].map(it => it.key)
export const CATEGORIES_COMPETENCES_CREATURES = {
generale: { key: 'generale', base: 0, label: "Générale" },
naturelle: { key: 'naturelle', base: 0, label: "Arme naturelle" },
melee: { key: 'melee', base: 0, label: "Mêlée" },
parade: { key: 'parade', base: 0, label: "Parade" },
tir: { key: 'tir', base: 0, label: "Tir" },
lancer: { key: 'lancer', base: 0, label: "Lancer" },
possession: { key: 'possession', base: 0, label: "Possession" },
}
+13 -6
View File
@@ -71,21 +71,25 @@ export class RdDItemBlessure extends RdDItem {
return 0
}
static async createBlessure(actor, gravite, localisation = '', attackerToken) {
const definition = RdDItemBlessure.getDefinition(gravite)
const blessure = {
static async createBlessure(actor, gravite, localisation = '', attackerToken = undefined) {
const blessure = RdDItemBlessure.prepareBlessure(gravite, localisation, attackerToken);
const blessures = await actor.createEmbeddedDocuments('Item', [blessure])
return blessures[0]
}
static prepareBlessure(gravite, localisation, attackerToken) {
const definition = RdDItemBlessure.getDefinition(gravite);
return {
name: definition.label,
type: 'blessure',
img: definition.icon,
system: {
gravite: gravite,
difficulte: - gravite,
difficulte: -gravite,
localisation: localisation,
origine: attackerToken?.name ?? ""
}
}
const blessures = await actor.createEmbeddedDocuments('Item', [blessure])
return blessures[0]
}
static async createTacheSoinBlessure(actor, gravite) {
@@ -209,6 +213,9 @@ export class RdDItemBlessure extends RdDItem {
isCritique() {
return this.system.gravite > 4 && this.system.gravite <= 6
}
isBleeding() {
return this.system.gravite > 2 && !this.system.premierssoins.done
}
isMort() {
return this.system.gravite > 6
}
+3 -2
View File
@@ -12,12 +12,13 @@ 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,
filter: it => Misc.toInt(it.system.quantite) > 0 || it.parent?.type == ACTOR_TYPES.commerce,
action: (item, actor) => item.proposerVente()
}
const _ACHETER = {
code: 'item-acheter', label: 'Acheter', icon: it => 'fa-regular fa-coins',
filter: it => Misc.toInt(it.system.quantite) > 0 && it.parent?.type == ACTOR_TYPES.commerce,
filter: it => it.parent?.type == ACTOR_TYPES.commerce,
allowLimited: true,
action: (item, actor) => actor.vente(item)
}
const _MONTRER = {
+41
View File
@@ -0,0 +1,41 @@
import { Grammar } from "../grammar.js";
import { RdDInitiative } from "../initiative.mjs";
export class MappingCreatureArme {
/* -------------------------------------------- */
static setRollDataCreature(rollData) {
const code = Grammar.toLowerCaseNoAccentNoSpace(rollData.competence.name);
const selectedCarac = { code: code, label: rollData.competence.name, value: rollData.competence.system.carac_value };
rollData.carac = { [code]: selectedCarac }
rollData.competence.system.defaut_carac = code
rollData.selectedCarac = selectedCarac
rollData.arme = MappingCreatureArme.armeCreature(rollData.competence);
}
/* -------------------------------------------- */
static armeCreature(item) {
const categorieAttaque = item.getCategorieAttaque()
if (categorieAttaque != undefined) {
// cloner pour ne pas modifier la compétence
return foundry.utils.mergeObject(item, {
action: item.isCompetencePossession() ? 'possession' : 'attaque',
system: {
competence: item.name,
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
niveau: item.system.niveau,
initiative: RdDInitiative.getRollInitiative(item.system.carac_value, item.system.niveau),
equipe: true,
resistance: 100,
dommagesReels: item.system.dommages,
penetration: 0,
force: 0,
rapide: true,
}
}, { inplace: false, });
}
return undefined;
}
}
+4 -4
View File
@@ -6,8 +6,8 @@ const tableEffets = [
{ code: "passeur", resultat: "succes", description: "Déplacer le demi-rêve à (force) cases", method: EffetsRencontre.passeur},
{ code: "reve+f", resultat: "succes", description: "Gain de (force) points de rêve" , method: EffetsRencontre.reve_plus_force},
{ code: "teleport", resultat: "succes", description: "Déplacer le demi-rêve (même type)", method: EffetsRencontre.teleportation_typecase },
{ code: "part+tete", resultat: "succes", description: "Tête de dragon sur réussite particulière", method: EffetsRencontre.rdd_part_tete },
{ code: "part+xp", resultat: "succes", description: "Expérience sur réussite particulière", method: EffetsRencontre.experience_particuliere },
{ code: "part+tete", resultat: "succes", description: "Tête de dragon sur particulière", method: EffetsRencontre.rdd_part_tete },
{ code: "part+xp", resultat: "succes", description: "Expérience sur particulière", method: EffetsRencontre.experience_particuliere },
{ code: "seuil", resultat: "succes", description: "Récupération de seuil de rêve", method: EffetsRencontre.regain_seuil },
{ code: "reve-1", resultat: "echec", description: "Perte de 1 point de rêve", method: EffetsRencontre.reve_moins_1 },
@@ -19,7 +19,7 @@ const tableEffets = [
{ code: "aleatoire", resultat: "echec", description: "Déplacement aléatoire", method: EffetsRencontre.deplacement_aleatoire },
{ code: "sort-aleatoire", resultat: "echec", description: "Déclenche un sort en réserve aléatoire", method: EffetsRencontre.sort_aleatoire },
{ code: "rompu", resultat: "echec", description: "Demi-rêve interrompu", method: EffetsRencontre.demireve_rompu },
{ code: "echec-queue", resultat: "echec", description: "Queue(s) de dragon sur échec", method: EffetsRencontre.rdd_echec_queue },
{ code: "echec-queue", resultat: "echec", description: "Queue(s) de dragon", method: EffetsRencontre.rdd_echec_queue },
{ code: "reve+1", resultat: "succes", description: "Gain de 1 point de rêve", method: EffetsRencontre.reve_plus_1 },
{ code: "vie-f", resultat: "echec", description: "Perte de (force) points de vie", method: EffetsRencontre.vie_moins_force },
@@ -68,7 +68,7 @@ export class RdDRencontre extends RdDItem {
}
static async appliquer(codes, tmrDialog, rencData) {
for(const effet of RdDRencontre.mapEffets(codes)){
for(let effet of RdDRencontre.mapEffets(codes)){
await effet.method(tmrDialog, rencData);
}
}
+23
View File
@@ -34,6 +34,13 @@ export class Misc {
return ((n % m) + m) % m;
}
static inRange(value, min, max) {
if (min > max) {
return Misc.inRange(value, max, min)
}
return Math.max(min, Math.min(value, max))
}
static sum() {
return (a, b) => Number(a) + Number(b);
}
@@ -58,6 +65,10 @@ export class Misc {
return 0;
}
static fakeId(base) {
return (base + foundry.utils.randomID(16)).substring(0, 16)
}
static typeName(type, subType) {
return subType ? game.i18n.localize(`TYPES.${type}.${subType}`)
: '';
@@ -108,6 +119,10 @@ export class Misc {
list.forEach(it => addToObj(obj, it))
return obj;
}
static indexed(list, index = 'index') {
let i = 0;
return list.map(it => { it[index] = i++; return it })
}
static concat(lists) {
return lists.reduce((a, b) => a.concat(b), []);
@@ -214,6 +229,14 @@ export class Misc {
return undefined
}
static async doIfOwner(document, action, orElse = async it => { ui.notifications.warn(`Vous n'avez pas le droit d'agir pour ${it.name}`) }) {
if (Misc.isOwnerPlayer(document)) {
return await action(document)
} else {
return await orElse(document)
}
}
static isOwnerPlayer(document) {
return document.testUserPermission && document.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)
}
+58 -29
View File
@@ -1,21 +1,26 @@
import { RdDCarac } from "./rdd-carac.js";
import { RDD_CONFIG } from "./constants.js";
import { RdDItemArme } from "./item/arme.js";
import { RdDPossession } from "./rdd-possession.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
const conditionsTactiques = [
{ type: '', descr: '', dmg: 0, attaque: 0, parade: 0, esquive: true },
{ type: 'charge', descr: 'Charge', dmg: 2, attaque: 4, parade: -4, esquive: false },
{ type: 'feinte', descr: 'Feinte', dmg: 1, attaque: 1, parade: 0, esquive: true },
{ type: 'pret', descr: 'prêt', dmg: 0, attaque: 0, parade: 0, esquive: true },
{ type: 'demi', descr: 'Demi-surprise', dmg: 1, attaque: 0, parade: 0, esquive: true },
{ type: 'totale', descr: 'Surprise totale', dmg: 10, attaque: 6, parade: 0, esquive: true },
{ key: '', label: '', dmg: 0, attaque: 0, parade: 0, esquive: true, isTactique: false },
{ key: 'normale', label: 'Attaque normale', dmg: 0, attaque: 0, parade: 0, esquive: true, isTactique: true },
{ key: 'charge', label: 'Charge', dmg: 2, attaque: 4, parade: -4, esquive: false, isTactique: true },
{ key: 'feinte', label: 'Feinte', dmg: 1, attaque: 1, parade: 0, esquive: true, isTactique: true },
{ key: 'pret', label: 'prêt', dmg: 0, attaque: 0, parade: 0, esquive: true, isTactique: false },
{ key: 'demi', label: 'Demi-surprise', dmg: 1, attaque: 0, parade: 0, esquive: true, isTactique: false },
{ key: 'totale', label: 'Surprise totale', dmg: 10, attaque: 6, parade: 0, esquive: true, isTactique: false },
];
/* -------------------------------------------- */
export class RdDBonus {
static get tactiques() {
return conditionsTactiques.filter(it => it.isTactique)
}
/* -------------------------------------------- */
static find(condition) {
return conditionsTactiques.find(e => e.type == condition) || conditionsTactiques.find(e => e.type == 'pret');
return conditionsTactiques.find(e => e.key == condition) || conditionsTactiques[0];
}
@@ -31,49 +36,73 @@ export class RdDBonus {
}
/* -------------------------------------------- */
static dmg(rollData, actor, isEntiteIncarnee = false) {
const dmgArme = RdDBonus.dmgArme(rollData.arme)
static dmg(rollData, actor) {
const diff = rollData.diffLibre;
const dmgArme = RdDBonus.dmgArme(rollData.arme, rollData.arme?.system.dommagesReels)
const forceRequise = rollData.arme ? RdDItemArme.valeurMain(rollData.arme.system.force ?? 0, RdDItemArme.getMainAttaque(rollData.competence)) : 0
let dmg = {
total: 0,
dmgArme: dmgArme,
diff: diff,
dmgDiffLibre: ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(diff ?? 0) : 0,
penetration: RdDBonus._peneration(rollData),
dmgTactique: RdDBonus.dmgBonus(rollData.tactique),
dmgParticuliere: RdDBonus._dmgParticuliere(rollData),
dmgSurprise: RdDBonus.dmgBonus(rollData.ajustements?.attaqueDefenseurSurpris.used),
mortalite: RdDBonus._calculMortalite(rollData, isEntiteIncarnee),
dmgActor: RdDBonus.bonusDmg(actor, rollData.selectedCarac?.label.toLowerCase(), dmgArme)
dmgSurprise: RdDBonus.dmgBonus(rollData.ajustements?.attaqueDefenseurSurpris?.used),
mortalite: RdDBonus.mortalite(rollData.dmg?.mortalite, rollData.arme?.system.mortalite),
dmgActor: RdDBonus.bonusDmg(actor, rollData.selectedCarac?.label.toLowerCase(), dmgArme),
dmgForceInsuffisante: Math.min(0, actor.getForce() - forceRequise)
}
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere;
return dmg;
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere + dmg.dmgForceInsuffisante
return dmg
}
static dmgRollV2(rollData, attaque) {
const actor = rollData.active.actor
const arme = attaque.arme
const dmgArme = RdDBonus.dmgArme(arme, attaque.dommages)
const dmg = {
total: 0,
dmgArme: dmgArme,
penetration: arme?.system.penetration ?? 0,
diff: attaque.diff,
dmgTactique: attaque.tactique?.dmg ?? 0,
dmgParticuliere: RdDBonus._dmgParticuliere(rollData),
dmgSurprise: rollData.opponent?.surprise?.dmg ?? 0,
mortalite: RdDBonus.mortalite(attaque.dmg?.mortalite, arme?.system.mortalite),
dmgActor: RdDBonus.bonusDmg(actor, attaque.carac.key, dmgArme, attaque.forceRequise),
dmgForceInsuffisante: Math.min(0, actor.getForce() - (attaque.forceRequise ?? 0)),
dmgDiffLibre: ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(attaque.diff ?? 0) : 0
}
dmg.isEmpoignade = dmg.mortalite == RDD_CONFIG.encaissement.empoignade
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere + dmg.dmgForceInsuffisante + dmg.dmgDiffLibre
return dmg
}
/* -------------------------------------------- */
static description(condition) {
return RdDBonus.find(condition).descr;
return RdDBonus.find(condition).label
}
/* -------------------------------------------- */
static dmgBonus(condition) {
return RdDBonus.find(condition).dmg;
return RdDBonus.find(condition).dmg
}
/* -------------------------------------------- */
static bonusAttaque(condition) {
return RdDBonus.find(condition).attaque;
return RdDBonus.find(condition).attaque
}
/* -------------------------------------------- */
static _calculMortalite(rollData, isEntiteIncarnee) {
return isEntiteIncarnee ? "entiteincarnee"
: rollData.dmg?.mortalite
?? rollData.arme?.system.mortalite
?? "mortel";
static mortalite(mortaliteSelect, mortaliteArme) {
return mortaliteSelect ?? mortaliteArme ?? RDD_CONFIG.encaissement.mortel
}
/* -------------------------------------------- */
static dmgArme(arme) {
static dmgArme(arme, dommages) {
if (arme) {
let dmgBase = arme.system.dommagesReels ?? Number(arme.system.dommages ?? 0);
let dmgBase = dommages ?? Number(arme.system.dommages ?? 0);
//Le bonus dégats magiques ne peut pas faire dépasser le bonus de l'arme (cf p.278)
return dmgBase + Math.min(dmgBase, arme.system.magique ? arme.system.ecaille_efficacite : 0);
}
@@ -87,13 +116,13 @@ export class RdDBonus {
/* -------------------------------------------- */
static bonusDmg(actor, categorie, dmgArme) {
const dmgActor = actor.getBonusDegat()
if (categorie == undefined) {
return 0
}
const dmgActor = actor.getBonusDegat()
switch (categorie) {
case "tir": return 0;
case "lancer": return Math.max(0, Math.min(dmgArme, dmgActor));
case "(tir)": case "tir": return 0
case "(lancer)": case "lancer": return Math.max(0, Math.min(dmgArme, dmgActor));
}
return dmgActor;
}
+20 -11
View File
@@ -52,6 +52,15 @@ export const CARACS = {
EMPATHIE: 'empathie',
REVE: 'reve',
CHANCE: 'chance',
PROTECTION: 'protection',
BEAUTE: 'beaute',
PERCEPTION: 'perception',
MELEE: 'melee',
TIR: 'tir',
LANCER: 'lancer',
DEROBEE: 'derobee',
CHANCE_ACTUELLE: 'chance-actuelle',
REVE_ACTUEL: 'reve-actuel',
}
export const LIST_CARAC_PERSONNAGE = {
[CARACS.TAILLE]: { code: CARACS.TAILLE, label: 'Taille', isCarac: true, path: 'system.carac.taille.value' },
@@ -68,21 +77,21 @@ export const LIST_CARAC_PERSONNAGE = {
[CARACS.EMPATHIE]: { code: CARACS.EMPATHIE, label: 'Empathie', isCarac: true, path: 'system.carac.empathie.value' },
[CARACS.REVE]: { code: CARACS.REVE, label: 'Rêve', isCarac: true, path: 'system.carac.reve.value' },
[CARACS.CHANCE]: { code: CARACS.CHANCE, label: 'Chance', isCarac: true, path: 'system.carac.chance.value' },
'protection': { code: 'protection', label: 'Protection naturelle', isCarac: false, path: 'system.attributs.protection.value' },
'beaute': { code: 'beaute', label: 'Beauté', isCarac: false, path: 'system.background.beaute.value' }
[CARACS.PROTECTION]: { code: CARACS.PROTECTION, label: 'Protection naturelle', isCarac: false, path: 'system.attributs.protection.value' },
[CARACS.BEAUTE]: { code: CARACS.BEAUTE, label: 'Beauté', isCarac: false, path: 'system.background.beaute.value' }
}
export const LIST_CARAC_AUTRES = {
'perception': { code: 'perception', label: 'Perception', path: 'system.carac.perception.value' },
[CARACS.PERCEPTION]: { code: 'perception', label: 'Perception', path: 'system.carac.perception.value' },
}
const LIST_CARAC_DERIVEE = {
'melee': { code: "melee", label: 'Mêlée', path: 'system.carac.melee.value' },
'tir': { code: "tir", label: 'Tir', path: 'system.carac.tir.value' },
'lancer': { code: "lancer", label: 'Lancer', path: 'system.carac.lancer.value' },
'derobee': { code: "derobee", label: 'Dérobée', path: 'system.carac.derobee.value' },
'chance-actuelle': { code: "chance-actuelle", label: 'Chance actuelle', path: 'system.carac.lancer.value' },
'reve-actuel': { code: "reve-actuel", label: 'Rêve actuel', path: 'system.reve.reve.value' },
[CARACS.MELEE]: { code: CARACS.MELEE, label: 'Mêlée', path: 'system.carac.melee.value' },
[CARACS.TIR]: { code: CARACS.TIR, label: 'Tir', path: 'system.carac.tir.value' },
[CARACS.LANCER]: { code: CARACS.LANCER, label: 'Lancer', path: 'system.carac.lancer.value' },
[CARACS.DEROBEE]: { code: CARACS.DEROBEE, label: 'Dérobée', path: 'system.carac.derobee.value' },
[CARACS.CHANCE_ACTUELLE]: { code: CARACS.CHANCE_ACTUELLE, label: 'Chance actuelle', path: 'system.carac.lancer.value' },
[CARACS.REVE_ACTUEL]: { code: CARACS.REVE_ACTUEL, label: 'Rêve actuel', path: 'system.reve.reve.value' },
}
export const LIST_CARAC_ROLL = Object.values(LIST_CARAC_PERSONNAGE).filter(it => it.isCarac && it.code != 'taille')
@@ -125,11 +134,11 @@ export class RdDCarac {
}
static isIntellect(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel) == 'intellect';
return Grammar.toLowerCaseNoAccent(caracLabel) == CARACS.INTELLECT
}
static isVolonte(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel) == 'volonte';
return Grammar.toLowerCaseNoAccent(caracLabel) == CARACS.VOLONTE
}
static isChance(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel)?.match(/chance(( |-)?actuelle)?/);
+346 -156
View File
@@ -1,5 +1,5 @@
import { ChatUtility } from "./chat-utility.js";
import { ENTITE_BLURETTE, HIDE_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { HIDE_DICE, renderTemplate, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { RdDBonus } from "./rdd-bonus.js";
@@ -7,14 +7,18 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDRoll } from "./rdd-roll.js";
import { RdDRollTables } from "./rdd-rolltables.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { STATUSES } from "./settings/status-effects.js";
import { Targets } from "./targets.js";
import { RdDEmpoignade } from "./rdd-empoignade.js";
import { RdDRollResult } from "./rdd-roll-result.js";
import { RdDItemArme } from "./item/arme.js";
import { EMPOIGNADE, RdDItemArme } from "./item/arme.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { RdDInitiative } from "./initiative.mjs";
import { MAP_PHASE, RdDInitiative } from "./initiative.mjs";
import RollDialog from "./roll/roll-dialog.mjs";
import { PART_DEFENSE } from "./roll/roll-part-defense.mjs";
import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll/roll-constants.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js";
import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs";
import { RollBasicParts } from "./roll/roll-basic-parts.mjs";
/* -------------------------------------------- */
const premierRoundInit = [
@@ -52,6 +56,12 @@ export class RdDCombatManager extends Combat {
}
}
static getCombatant(actorId, tokenId) {
return game.combat?.combatants.find(it => it.actor.id == actorId &&
it.token.id == tokenId
)
}
/* -------------------------------------------- */
async nextRound() {
await this.finDeRound();
@@ -63,7 +73,7 @@ export class RdDCombatManager extends Combat {
if (Misc.isFirstConnectedGM()) {
await this.finDeRound({ terminer: true })
ChatUtility.removeChatMessageContaining(`<div data-combatid="${this.id}" data-combatmessage="actor-turn-summary">`)
game.messages.filter(m => ChatUtility.getMessageData(m, 'attacker-roll') != undefined && ChatUtility.getMessageData(m, 'defender-roll') != undefined)
game.messages.filter(m => ChatUtility.getMessageData(m, 'rollData') != undefined && ChatUtility.getMessageData(m, 'rollData') != undefined)
.forEach(it => it.delete())
RdDEmpoignade.deleteAllEmpoignades()
}
@@ -95,21 +105,25 @@ export class RdDCombatManager extends Combat {
}
else if (!combatant.actor.isActorCombat()) {
if (options.warning) {
ui.notifications.warn(`${combatant.name} ne peut pas combattre!`)
ui.notifications.warn(`L'acteur ${combatant.name} ne peut pas combattre!`)
}
return undefined
}
return combatant.actor
}
static calculAjustementInit(actor, arme) {
const efficacite = (arme?.system.magique) ? arme.system.ecaille_efficacite : 0
const etatGeneral = actor.getEtatGeneral() ?? 0
return efficacite + etatGeneral
static bonusArme(arme) {
return (arme?.system.magique) ? arme.system.ecaille_efficacite : 0
}
/************************************************************************************/
static etatGeneral(actor) {
return actor.getEtatGeneral() ?? 0;
}
/** ***********************************************************************************
* @override lance l'initiative de plusieurs combattants (tous/ous les PNJs) en une fois
*/
async rollInitiative(ids, messageOptions = {}) {
console.log(`${game.system.title} | Combat.rollInitiative()`, ids, messageOptions)
ids = typeof ids === "string" ? [ids] : ids
@@ -117,18 +131,17 @@ export class RdDCombatManager extends Combat {
return this
}
async rollInitRdD(id, formula, messageOptions = {}) {
async rollInitRdD(id, formule, messageOptions = {}) {
const combatant = this.combatants.get(id);
const actor = RdDCombatManager.getActorCombatant(combatant)
if (actor) {
const rollFormula = formula ?? RdDCombatManager.getFirstInitRollFormula(actor)
const roll = combatant.getInitiativeRoll(rollFormula);
if (!roll.total) {
await roll.evaluate();
}
const total = Math.max(roll.total, 0.00);
console.log("Compute init for", rollFormula, roll, total, combatant);
await this.updateEmbeddedDocuments("Combatant", [{ _id: combatant._id || combatant.id, initiative: total }]);
formule = formule ?? RdDCombatManager.getFirstInitRollFormula(actor)
const init = await RdDInitiative.roll(formule)
await this.updateEmbeddedDocuments("Combatant", [{
_id: combatant._id || combatant.id,
initiative: init.init, 'system.init': init
}])
// Send a chat message
let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode");
@@ -140,10 +153,10 @@ export class RdDCombatManager extends Combat {
alias: combatant.token?.name,
sound: CONFIG.sounds.dice,
},
flavor: `${combatant.token?.name} a fait son jet d'Initiative (${messageOptions.info})<br>`
flavor: `${combatant.token?.name} a une initiatyive de ${init.value} : ${messageOptions.info}<br>`
},
messageOptions);
roll.toMessage(messageData, { rollMode, create: true });
init.roll.toMessage(messageData, { rollMode, create: true });
RdDCombatManager.processPremierRoundInit();
}
@@ -155,16 +168,11 @@ export class RdDCombatManager extends Combat {
if (actions.length > 0) {
const action = actions[0]
const init = RdDCombatManager.getInitData(actor, action)
const ajustement = RdDCombatManager.calculAjustementInit(actor, action)
return RdDCombatManager.formuleInitiative(init.offset, init.carac, init.niveau, ajustement);
const ajustement = RdDCombatManager.bonusArme(action.arme) + RdDCombatManager.etatGeneral(actor)
return RdDInitiative.formule(init.phase, init.carac, init.niveau, ajustement);
}
let ajustement = RdDCombatManager.calculAjustementInit(actor, undefined);
return RdDCombatManager.formuleInitiative(2, 10, 0, ajustement);
}
static formuleInitiative(rang, carac, niveau, bonusMalus) {
return `${rang} +( (${RdDInitiative.calculInitiative(niveau, carac, bonusMalus)} )/100)`;
return RdDInitiative.formule(MAP_PHASE['autre'], 10, 0, actor.getEtatGeneral() ?? 0);
}
/* -------------------------------------------- */
@@ -176,7 +184,6 @@ export class RdDCombatManager extends Combat {
for (let combatant of game.combat.combatants) {
if (combatant.initiativeData?.arme?.type == "arme") {
// TODO: get init data premier round
const initiativeData = combatant.initiativeData;
const action = combatant.initiativeData.arme;
const fromArme = Grammar.toLowerCaseNoAccentNoSpace(action.system.initpremierround)
const initData = premierRoundInit.find(it => fromArme.includes(initData.pattern))
@@ -196,10 +203,27 @@ export class RdDCombatManager extends Combat {
}
/* -------------------------------------------- */
static incDecInit(combatantId, incDecValue) {
const combatant = game.combat.combatants.get(combatantId);
let initValue = combatant.initiative + incDecValue;
game.combat.setInitiative(combatantId, initValue);
static applyInitiativeCommand(combatantId, command, commandValue) {
switch (command) {
case 'delta': return RdDCombatManager.incDecInit(combatantId, commandValue);
case 'autre': return RdDCombatManager.rollInitiativeAction(combatantId,
{ name: "Autre action", action: 'autre', system: { initOnly: true, competence: "Autre action" } });
}
}
static async incDecInit(combatantId, incDecValue) {
const combatant = game.combat.combatants.get(combatantId)
if (combatant?.initiative && incDecValue != 0) {
const value = combatant.system.init.value + incDecValue
const newInit = combatant.initiative + incDecValue / 100;
await game.combat.updateEmbeddedDocuments("Combatant", [{
_id: combatantId,
initiative: newInit,
'system.init.value': value,
'system.init.init': newInit,
}])
}
}
/* -------------------------------------------- */
@@ -216,56 +240,42 @@ export class RdDCombatManager extends Combat {
}
}
options = [
{ name: "Incrémenter initiative", condition: true, icon: '<i class="fa-solid fa-plus"></i>', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), +0.01); } },
{ name: "Décrémenter initiative", condition: true, icon: '<i class="fa-solid fa-minus"></i>', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), -0.01); } }
{ name: "Incrémenter initiative", condition: true, icon: '<i class="fa-solid fa-plus"></i>', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), +1); } },
{ name: "Décrémenter initiative", condition: true, icon: '<i class="fa-solid fa-minus"></i>', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), -1); } }
].concat(options);
}
/* -------------------------------------------- */
static async rollInitiativeAction(combatantId, action) {
const combatant = game.combat.combatants.get(combatantId)
const actor = RdDCombatManager.getActorCombatant(combatant)
if (actor == undefined) { return [] }
combatant.initiativeData = { arme: action } // pour reclasser l'init au round 0
if (actor == undefined) { return }
const init = RdDCombatManager.getInitData(actor, action)
const ajustement = RdDCombatManager.calculAjustementInit(actor, action.arme)
const rollFormula = RdDCombatManager.formuleInitiative(init.offset, init.carac, init.niveau, ajustement);
const ajustement = RdDCombatManager.bonusArme(actor, action.arme) + RdDCombatManager.etatGeneral(actor)
const formule = RdDInitiative.formule(init.phase, init.carac, init.niveau, ajustement);
await game.combat.rollInitRdD(combatantId, rollFormula, init);
combatant.initiativeData
await game.combat.rollInitRdD(combatantId, formule, init);
combatant.initiativeData = { action, formule } // pour reclasser l'init au round 0
}
static getInitData(actor, action) {
if (actor.getSurprise() == "totale") { return { offset: -1, info: "Surprise Totale", carac: 0, niveau: 0 } }
if (actor.getSurprise() == "demi") { return { offset: 0, info: "Demi Surprise", carac: 0, niveau: 0 } }
if (action.action == 'autre') { return { offset: 2, info: "Autre Action", carac: 0, niveau: 0 } }
if (action.action == 'possession') { return { offset: 10, info: "Possession", carac: actor.getReveActuel(), niveau: 0 } }
if (action.action == 'haut-reve') { return { offset: 9, info: "Draconic", carac: actor.getReveActuel(), niveau: 0 } }
if (actor.getSurprise() == "totale") { return { phase: MAP_PHASE['totale'], info: "Surprise Totale", carac: 0, niveau: 0 } }
if (actor.getSurprise() == "demi") { return { phase: MAP_PHASE['demi'], info: "Demi Surprise", carac: 0, niveau: 0 } }
if (action.action == 'autre') { return { phase: MAP_PHASE['autre'], info: "Autre Action", carac: 0, niveau: 0 } }
if (action.action == 'possession') { return { phase: MAP_PHASE['possession'], info: "Possession", carac: actor.getReveActuel(), niveau: 0 } }
if (action.action == 'haut-reve') { return { phase: MAP_PHASE['draconic'], info: "Draconic", carac: actor.getReveActuel(), niveau: 0 } }
const comp = action.comp
return {
offset: RdDCombatManager.initOffset(comp?.system.categorie, action.arme),
info: action.name + " / " + comp.name,
phase: RdDInitiative.phaseArme(comp?.system.categorie, action.arme),
info: action.label,
carac: actor.getCaracInit(comp),
niveau: comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(action.main) ? -8 : -6)
}
}
static initOffset(categorie, arme) {
switch (categorie) {
case "tir": return 8
case "lancer": return 7
default:
switch (arme.system.cac) {
case "empoignade": return 3
case "pugilat": return 4
case "naturelle": return 4
default: return 5
}
}
}
/* -------------------------------------------- */
static displayInitiativeMenu(html, combatantId) {
const combatant = game.combat.combatants.get(combatantId)
@@ -293,13 +303,8 @@ export class RdDCombatManager extends Combat {
? possessions
: actor.listActions({ isEquipe: true })
for (let index = 0; index < actions.length; index++) {
actions[index].index = index
}
return actions
return Misc.indexed(actions)
}
}
/* -------------------------------------------- */
@@ -310,6 +315,7 @@ export class RdDCombat {
switch (sockmsg.msg) {
case "msg_encaisser": return RdDCombat.onMsgEncaisser(sockmsg.data);
case "msg_defense": return RdDCombat.onMsgDefense(sockmsg.data);
case "msg_defense_v2": return RdDCombat.onMsgDefenseV2(sockmsg.data);
}
}
@@ -362,13 +368,26 @@ export class RdDCombat {
return new RdDCombat(attacker, attackerTokenId, defender, defenderTokenId, target)
}
static rddCombatForAttackV2(attackerRoll) {
const defenderRoll = RollBasicParts.prepareDefense(attackerRoll)
return RdDCombat.rddCombatForDefenseV2(defenderRoll)
}
static rddCombatForDefenseV2(defenderRoll) {
let defenderToken = canvas.tokens.get(defenderRoll.active.tokenId)
if (defenderToken) {
return RdDCombat.rddCombatForAttackerAndDefender(defenderRoll.opponent.id, defenderRoll.opponent.tokenId, defenderRoll.active.tokenId)
}
}
/* -------------------------------------------- */
static onMsgEncaisser(msg) {
let defender = canvas.tokens.get(msg.defenderToken.id).actor;
if (Misc.isOwnerPlayer(defender)) {
let attackerRoll = msg.attackerRoll;
let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : undefined;
defender.encaisserDommages(attackerRoll, attacker, msg.attackerToken);
defender.encaisserDommages(attackerRoll.dmg, attacker, msg.attackerToken);
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id);
rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
}
@@ -379,8 +398,13 @@ export class RdDCombat {
let defenderToken = canvas.tokens.get(msg.defenderToken.id)
if (defenderToken && Misc.isFirstConnectedGM()) {
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id)
rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme)
rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll)
rddCombat?.removeChatMessageActionsPasseArme(msg.paramChatDefense.attackerRoll.passeArme)
if (msg.defenderRoll.v2) {/* TODO: delete roll V1 */
RollDialog.loadRollData(msg.paramChatDefense)
rddCombat?._chatMessageDefenseV2(msg.paramChatDefense)
} else {
rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll)
}
}
}
@@ -398,15 +422,18 @@ export class RdDCombat {
/* -------------------------------------------- */
static registerChatCallbacks(html) {
for (let button of [
'.parer-button',
'.esquiver-button',
'.button-parade',
'.button-esquive',
'.button-encaisser',
'.particuliere-attaque',
'.encaisser-button',
'.appel-chance-defense',
'.appel-destinee-defense',
'.appel-chance-attaque',
'.appel-destinee-attaque',
'.echec-total-attaque',
// '.appel-chance',
// '.chat-encaissement',
// '.resister-recul',
]) {
$(html).on("click", button, event => {
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(
@@ -456,8 +483,8 @@ export class RdDCombat {
/* -------------------------------------------- */
async onEvent(button, event) {
const chatMessage = ChatUtility.getChatMessage(event);
const defenderRoll = ChatUtility.getMessageData(chatMessage, 'defender-roll');
const attackerRoll = defenderRoll?.attackerRoll ?? ChatUtility.getMessageData(chatMessage, 'attacker-roll');
const defenderRoll = ChatUtility.getMessageData(chatMessage, 'rollData');
const attackerRoll = defenderRoll?.attackerRoll ?? ChatUtility.getMessageData(chatMessage, 'rollData');
console.log('RdDCombat', attackerRoll, defenderRoll);
const armeParadeId = event.currentTarget.attributes['data-armeid']?.value;
@@ -466,9 +493,9 @@ export class RdDCombat {
switch (button) {
case '.particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value);
case '.parer-button': return this.parade(attackerRoll, armeParadeId);
case '.esquiver-button': return this.esquive(attackerRoll, compId, competence);
case '.encaisser-button': return this.encaisser(attackerRoll, defenderRoll);
case '.button-parade': return this.parade(attackerRoll, armeParadeId);
case '.button-esquive': return this.esquive(attackerRoll, compId, competence);
case '.button-encaisser': return this.encaisser(attackerRoll, defenderRoll);
case '.echec-total-attaque': return this._onEchecTotal(attackerRoll);
case '.appel-chance-attaque': return this.attacker.rollAppelChance(
@@ -478,11 +505,9 @@ export class RdDCombat {
() => this.defenseChanceuse(attackerRoll, defenderRoll),
() => this.afficherOptionsDefense(attackerRoll, defenderRoll, { defenseChance: true }));
case '.appel-destinee-attaque': return this.attacker.appelDestinee(
() => this.attaqueSignificative(attackerRoll),
() => { });
() => this.attaqueSignificative(attackerRoll));
case '.appel-destinee-defense': return this.defender.appelDestinee(
() => this.defenseDestinee(defenderRoll),
() => { });
() => this.defenseDestinee(defenderRoll));
}
}
@@ -552,33 +577,48 @@ export class RdDCombat {
/* -------------------------------------------- */
static isEchecTotal(rollData) {
if (!rollData.attackerRoll && rollData.ajustements.surprise.used) {
return rollData.rolled.isEchec && rollData.rolled.code != 'notSign';
if (rollData.v2 /* roll V2*/) {
// TODO: en cas de demi-surprise à l'attaque, tout échec est un echec total.
// TODO: en cas de demi-surprise en défense, pas de changement à la règle de base
return rollData.rolled.isETotal
}
return rollData.rolled.isETotal;
if (rollData.mode == ROLL_TYPE_ATTAQUE && rollData.surprise == 'demi') {
// échec normal à l'attaque en demi surprise
return rollData.rolled.isEchec && rollData.rolled.code != 'notSign'
}
return rollData.rolled.isETotal
}
/* -------------------------------------------- */
static isParticuliere(rollData) {
if (!rollData.attackerRoll && rollData.ajustements.surprise.used) {
return false;
if (rollData.v2 /* roll V2*/) {
return rollData.rolled.isPart
}
return rollData.rolled.isPart;
if (rollData.attackerRoll || !rollData.ajustements.surprise.used) {
return rollData.rolled.isPart
}
return false
}
/* -------------------------------------------- */
static isReussite(rollData) {
switch (rollData.ajustements.surprise.used) {
case 'totale': return false;
case 'demi': return rollData.rolled.isSign;
if (rollData.v2 /* roll V2*/) {
return rollData.rolled.isSuccess
}
return rollData.rolled.isSuccess;
if (!rollData.ajustements.surprise.used) {
return rollData.rolled.isSuccess
}
switch (rollData.ajustements.surprise.used) {
case 'totale': return false
case 'demi': return rollData.rolled.isSign
}
return rollData.rolled.isSuccess
}
/* -------------------------------------------- */
async proposerAjustementTirLancer(rollData) {
if (['tir', 'lancer'].includes(rollData.competence.system.categorie)) {
if (this.defender.isEntite([ENTITE_BLURETTE])) {
if (this.defender.isEntiteBlurette()) {
ChatMessage.create({
content: `<strong>La cible est une blurette, l'arme à distance sera perdue dans le blurêve`,
whisper: ChatUtility.getGMs()
@@ -642,12 +682,110 @@ export class RdDCombat {
return { msg: "à déterminer (0 immobile, -3 actif, -4 en mouvement, -5 en zig-zag)", diff: -3 };
}
async attaqueV2() {
if (!await this.attacker.accorder(this.defender, 'avant-attaque')) {
return
}
await this.doRollAttaque({
ids: {
actorId: this.attackerId,
actorTokenId: this.attackerTokenId,
opponentId: this.defender.id,
opponentTokenId: this.defenderTokenId,
},
type: { allowed: ['attaque'], current: 'attaque' },
passeArme: foundry.utils.randomID(16),
})
}
async doRollAttaque(rollData, callbacks = []) {
// TODO V2 await this.proposerAjustementTirLancer(rollData)
return await RollDialog.create(rollData, {
onRollDone: RollDialog.onRollDoneClose,
callbacks: [
async (roll) => await this.onAttaqueV2(roll),
...callbacks
]
})
}
async onAttaqueV2(attackerRoll) {
if (!this.defender || !attackerRoll.rolled.isSuccess || attackerRoll.particulieres?.length > 1) {
return
}
if (!await this.attacker.accorder(this.defender, 'avant-defense')) {
return;
}
RollDialog.loadRollData(attackerRoll)
const surpriseDefender = this.defender.getSurprise(true);
const paramChatDefense = {
attackerRoll: attackerRoll,
isPossession: this.isPossession(attackerRoll),
defender: this.defender,
attacker: this.attacker,
attackerId: this.attackerId,
attackerToken: this.attackerToken,
defenderToken: this.defenderToken,
surprise: surpriseDefender,
}
if (Misc.isFirstConnectedGM()) {
await this._chatMessageDefenseV2(paramChatDefense);
}
else {
this._socketSendMessageDefenseV2(paramChatDefense);
}
}
_socketSendMessageDefenseV2(paramChatDefense) {
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_defense_v2", data: {paramChatDefense} })
}
static async onMsgDefenseV2(msg) {
if (Misc.isFirstConnectedGM()) {
const paramChatDefense = msg.paramChatDefense
RollBasicParts.restore(paramChatDefense.attackerRoll)
const rddCombat = RdDCombat.rddCombatForAttackV2(paramChatDefense.attackerRoll)
rddCombat?.removeChatMessageActionsPasseArme(paramChatDefense.attackerRoll.passeArme)
await rddCombat?._chatMessageDefenseV2(paramChatDefense)
}
}
async _chatMessageDefenseV2(paramDemandeDefense) {
const attackerRoll = paramDemandeDefense.attackerRoll;
RollBasicParts.loadSurprises(attackerRoll)
attackerRoll.dmg = RdDBonus.dmgRollV2(attackerRoll, attackerRoll.current.attaque)
const defenseData = RollBasicParts.prepareDefense(attackerRoll)
const choixDefense = await ChatMessage.create({
// message privé: du défenseur à lui même (et aux GMs)
speaker: ChatMessage.getSpeaker(this.defender, canvas.tokens.get(this.defenderTokenId)),
alias: this.attacker?.getAlias(),
whisper: ChatUtility.getOwners(this.defender),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.hbs', defenseData)
});
// flag pour garder les jets d'attaque/defense
ChatUtility.setMessageData(choixDefense, 'demande-defense', true)
ChatUtility.setMessageData(choixDefense, 'rollData', {
ids: defenseData.ids,
attackerRoll: RollDialog.saveParts(attackerRoll),
passeArme: defenseData.passeArme
})
}
/* -------------------------------------------- */
async attaque(competence, arme) {
if (!await this.attacker.accorder(this.defender, 'avant-attaque')) {
return
}
if (arme.system.cac == 'empoignade') {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
return this.attacker.rollCompetence(competence.name, { arme: arme })
}
if (arme.system.cac == EMPOIGNADE) {
RdDEmpoignade.onAttaqueEmpoignade(this.attacker, this.defender)
return
}
@@ -679,6 +817,7 @@ export class RdDCombat {
/* -------------------------------------------- */
_prepareAttaque(competence, arme) {
let rollData = {
mode: ROLL_TYPE_ATTAQUE,
alias: this.attacker?.getAlias(),
passeArme: foundry.utils.randomID(16),
mortalite: arme?.system.mortalite,
@@ -690,8 +829,8 @@ export class RdDCombat {
essais: {}
};
if (this.attacker.isCreatureEntite()) {
RdDItemCompetenceCreature.setRollDataCreature(rollData);
if (this.attacker.isCreatureOuEntite()) {
MappingCreatureArme.setRollDataCreature(rollData);
}
else if (arme) {
// Usual competence
@@ -699,9 +838,9 @@ export class RdDCombat {
}
else {
// sans armes: à mains nues
rollData.arme = RdDItemArme.corpsACorps(this.attacker)
rollData.arme = RdDItemArme.pugilat(this.attacker)
rollData.arme.system.niveau = competence.system.niveau
rollData.arme.system.initiative = RdDInitiative.calculInitiative(competence.system.niveau, this.attacker.system.carac['melee'].value);
rollData.arme.system.initiative = RdDInitiative.getRollInitiative(this.attacker.system.carac['melee'].value, competence.system.niveau);
}
return rollData;
}
@@ -713,9 +852,6 @@ export class RdDCombat {
if (RdDCombat.isReussite(attackerRoll)) {
return await this._onAttaqueNormale(attackerRoll)
}
// if (RdDCombat.isParticuliere(attackerRoll) && attackerRoll.particuliere == undefined) {
// return
// }
if (RdDCombat.isEchecTotal(attackerRoll)) {
return await this._onAttaqueEchecTotal(attackerRoll)
}
@@ -755,14 +891,14 @@ export class RdDCombat {
passeArme: rollData.passeArme
})
});
ChatUtility.setMessageData(choixParticuliere, 'attacker-roll', rollData);
ChatUtility.setMessageData(choixParticuliere, 'rollData', rollData);
}
/* -------------------------------------------- */
async _onAttaqueNormale(attackerRoll) {
console.log("RdDCombat.onAttaqueNormale >>>", attackerRoll);
attackerRoll.dmg = RdDBonus.dmg(attackerRoll, this.attacker, this.defender.isEntite());
attackerRoll.dmg = RdDBonus.dmg(attackerRoll, this.attacker);
let defenderRoll = { attackerRoll: attackerRoll, passeArme: attackerRoll.passeArme, show: {} }
attackerRoll.show = {
cible: this.defender?.getAlias() ?? 'la cible',
@@ -781,13 +917,14 @@ export class RdDCombat {
/* -------------------------------------------- */
isPossession(attackerRoll) {
return attackerRoll.selectedCarac.label.toLowerCase() == 'possession';
const carac = attackerRoll.v2
? attackerRoll.current.carac?.label
: attackerRoll.selectedCarac.label
return carac?.toLowerCase() == 'possession';
}
/* -------------------------------------------- */
async _sendMessageDefense(attackerRoll, defenderRoll, essaisPrecedents = undefined) {
console.log("RdDCombat._sendMessageDefense", attackerRoll, defenderRoll, essaisPrecedents, " / ", this.attacker, this.target, this.attackerId, attackerRoll.competence.system.categorie);
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
if (essaisPrecedents) {
foundry.utils.mergeObject(attackerRoll.essais, essaisPrecedents, { overwrite: true });
@@ -833,10 +970,10 @@ export class RdDCombat {
speaker: ChatMessage.getSpeaker(this.defender, canvas.tokens.get(this.defenderTokenId)),
alias: this.attacker?.getAlias(),
whisper: ChatUtility.getOwners(this.defender),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.hbs', paramDemandeDefense),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense-v1.hbs', paramDemandeDefense),
});
// flag pour garder les jets d'attaque/defense
ChatUtility.setMessageData(choixDefense, 'defender-roll', defenderRoll);
ChatUtility.setMessageData(choixDefense, 'rollData', defenderRoll);
}
/* -------------------------------------------- */
@@ -850,14 +987,14 @@ export class RdDCombat {
defenderToken: this.defenderToken,
defenderRoll: defenderRoll,
paramChatDefense: paramChatDefense,
rollMode: true
rollMode: true,
}
});
}
/* -------------------------------------------- */
_filterArmesParade(defender, competence, armeAttaque) {
let defenses = defender.items.filter(it => RdDItemArme.isParade(it))
let defenses = defender.items.filter(it => it.isParade())
defenses = foundry.utils.duplicate(defenses)
defenses.forEach(armeDefense => {
// Ajout du # d'utilisation ce round
@@ -879,6 +1016,7 @@ export class RdDCombat {
const choixEchecTotal = await ChatMessage.create({
whisper: ChatUtility.getOwners(this.attacker),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.hbs', {
rolled: attackerRoll.rolled,
attackerId: this.attackerId,
attacker: this.attacker,
attackerToken: this.attackerToken,
@@ -886,7 +1024,7 @@ export class RdDCombat {
essais: attackerRoll.essais
})
});
ChatUtility.setMessageData(choixEchecTotal, 'attacker-roll', attackerRoll);
ChatUtility.setMessageData(choixEchecTotal, 'rollData', attackerRoll);
}
/* -------------------------------------------- */
@@ -946,9 +1084,43 @@ export class RdDCombat {
dialog.render(true);
}
async defenseV2(attackerRoll, callbacks = []) {
// this._prepareParade(attackerRoll, arme, competence);
RollDialog.loadRollData(attackerRoll)
await this.doRollDefense({
ids: {
actorId: this.defender.id,
actorTokenId: this.defenderTokenId,
opponentTokenId: this.attackerTokenId,
opponentId: this.attackerId,
},
type: { allowed: [ROLL_TYPE_DEFENSE], current: ROLL_TYPE_DEFENSE },
attackerRoll: attackerRoll,
passeArme: attackerRoll.passeArme,
}, callbacks)
}
async doRollDefense(rollData, callbacks = []) {
return await RollDialog.create(rollData, {
onRollDone: RollDialog.onRollDoneClose,
callbacks: [
async (roll) => {
this.removeChatMessageActionsPasseArme(roll.passeArme);
// defense: esquive / arme de parade / competence de défense
if (!RdDCombat.isParticuliere(roll)) {
await roll.active.actor.incDecItemUse(roll.current[PART_DEFENSE].defense?.id);
}
await this._onDefense(roll);
},
...callbacks
]
})
}
/* -------------------------------------------- */
_prepareParade(attackerRoll, armeParade, competenceParade) {
let defenderRoll = {
mode: ROLL_TYPE_DEFENSE,
alias: this.defender?.getAlias(),
passeArme: attackerRoll.passeArme,
diffLibre: attackerRoll.diffLibre,
@@ -964,13 +1136,48 @@ export class RdDCombat {
show: {}
};
if (this.defender.isCreatureEntite()) {
RdDItemCompetenceCreature.setRollDataCreature(defenderRoll);
if (this.defender.isCreatureOuEntite()) {
MappingCreatureArme.setRollDataCreature(defenderRoll);
}
return defenderRoll;
}
async _onDefense(rollData) {
const isEsquive = rollData.current[PART_DEFENSE].isEsquive
const isParade = !isEsquive
if (RdDCombat.isReussite(rollData)) {
if (isParade) {
await this.computeDeteriorationArme(rollData)
if (RdDCombat.isParticuliere(rollData)) {
await this.infoAttaquantDesarme(rollData)
}
}
}
this.removeChatMessageActionsPasseArme(rollData.passeArme)
}
async infoAttaquantDesarme(rollData) {
if (/*TODO: parade?*/!rollData.attackerRoll?.particuliere) {
// TODO: attaquant doit jouer résistance et peut être désarmé p132
ChatUtility.createChatWithRollMode(
{ content: `(à gérer) L'attaquant doit jouer résistance et peut être désarmé (p132)` },
this.defender)
}
}
async _onDefenseNormale(rollData) {
console.log("RdDCombat._onDefenseNormale >>>", rollData);
await this.computeRecul(rollData);
await this.computeDeteriorationArme(rollData);
await RdDRollResult.displayRollData(rollData, this.defender, 'chat-resultat-parade.hbs');
this.removeChatMessageActionsPasseArme(rollData.passeArme);
}
async _onParade(defenderRoll) {
if (RdDCombat.isReussite(defenderRoll)) {
@@ -1042,6 +1249,7 @@ export class RdDCombat {
/* -------------------------------------------- */
_prepareEsquive(attackerRoll, competence) {
let rollData = {
mode: ROLL_TYPE_DEFENSE,
alias: this.defender.getAlias(),
passeArme: attackerRoll.passeArme,
diffLibre: attackerRoll.diffLibre,
@@ -1055,8 +1263,8 @@ export class RdDCombat {
show: {}
};
if (this.defender.isCreatureEntite()) {
RdDItemCompetenceCreature.setRollDataCreature(rollData);
if (this.defender.isCreatureOuEntite()) {
MappingCreatureArme.setRollDataCreature(rollData);
}
return rollData;
}
@@ -1105,7 +1313,7 @@ export class RdDCombat {
// Est-ce une parade normale?
if (defenderRoll.arme && attackerRoll && !defenderRoll.rolled.isPart) {
// Est-ce que l'attaque est une particulière en force ou une charge
if (defenderRoll.needResist || this._isForceOuCharge(attackerRoll)) {
if (defenderRoll.needResist || this._isForceOuCharge(attackerRoll, defenderRoll.v2)) {
defenderRoll.show = defenderRoll.show || {}
@@ -1153,7 +1361,7 @@ export class RdDCombat {
finalLevel: Misc.toInt(defenderRoll.competence.system.niveau) - dmg,
showDice: HIDE_DICE
});
defenderRoll.show.desarme = desarme.rolled.isEchec;
defenderRoll.show.desarme = desarme.rolled.isEchec
}
}
}
@@ -1161,41 +1369,19 @@ export class RdDCombat {
/* -------------------------------------------- */
async computeRecul(defenderRoll) { // Calcul du recul (p. 132)
if (!ReglesOptionnelles.isUsing('recul')) {
return
}
const attackerRoll = defenderRoll.attackerRoll;
if (ReglesOptionnelles.isUsing('recul') && this._isForceOuCharge(attackerRoll)) {
const impact = this._computeImpactRecul(attackerRoll);
const rollRecul = await RdDResolutionTable.rollData({ caracValue: 10, finalLevel: impact });
if (rollRecul.rolled.isSuccess) {
defenderRoll.show.recul = 'encaisse';
} else if (rollRecul.rolled.isETotal || this._isReculCauseChute(impact)) {
defenderRoll.show.recul = 'chute';
await this.defender.setEffect(STATUSES.StatusProne, true);
}
else {
defenderRoll.show.recul = 'recul';
}
if (this._isForceOuCharge(attackerRoll, defenderRoll.v2)) {
defenderRoll.show.recul = this.defender.encaisserRecul(this.attacker.getForce(), attackerRoll.dmg.dmgArme)
}
}
/* -------------------------------------------- */
async _isReculCauseChute(impact) {
const agilite = this.defender.getAgilite();
const chute = await RdDResolutionTable.rollData({ caracValue: agilite, finalLevel: impact });
return chute.rolled.isEchec;
_isForceOuCharge(attaque, isRollV2 = false /* TODO: delete roll V1 */) {
return attaque.particuliere == 'force' || 'charge' == (isRollV2 ? attaque.tactique?.key : attaque.tactique)
}
/* -------------------------------------------- */
_isForceOuCharge(attaque) {
return attaque.particuliere == 'force' || attaque.tactique == 'charge';
}
/* -------------------------------------------- */
_computeImpactRecul(attaque) {
const taille = this.defender.getTaille();
const force = this.attacker.getForce();
const dommages = attaque.arme.system.dommagesReels ?? attaque.arme.system.dommages;
return taille - (force + dommages);
}
/* -------------------------------------------- */
async encaisser(attackerRoll, defenderRoll) {
@@ -1205,12 +1391,16 @@ export class RdDCombat {
this._onEchecTotal(defenderRoll);
}
await this.doRollEncaissement(attackerRoll, defenderRoll);
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
}
async doRollEncaissement(attackerRoll, defenderRoll) {
if (Misc.isOwnerPlayer(this.defender)) {
attackerRoll.attackerId = this.attackerId;
attackerRoll.defenderTokenId = this.defenderToken.id;
await this.computeRecul(defenderRoll);
await this.defender.encaisserDommages(attackerRoll, this.attacker, defenderRoll?.show, this.attackerToken, this.defenderToken);
await this.defender.encaisserDommages(attackerRoll.dmg, this.attacker, defenderRoll?.show, this.attackerToken, this.defenderToken);
}
else { // envoi à un GM: les joueurs n'ont pas le droit de modifier les personnages qu'ils ne possèdent pas
game.socket.emit(SYSTEM_SOCKET_ID, {
@@ -1221,9 +1411,8 @@ export class RdDCombat {
attackerToken: this.attackerToken,
defenderToken: this.defenderToken
}
});
})
}
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
}
/* -------------------------------------------- */
@@ -1255,4 +1444,5 @@ export class RdDCombat {
alias: alias
})
}
}
}
+4 -8
View File
@@ -19,6 +19,7 @@ import { TMRUtility } from "./tmr-utility.js";
import { DialogFatigueVoyage } from "./voyage/dialog-fatigue-voyage.js";
import { ChatUtility } from "./chat-utility.js";
import { RdDRollResult } from "./rdd-roll-result.js";
import { renderTemplate } from "./constants.js";
const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/;
@@ -126,7 +127,7 @@ export class RdDCommands {
<br><strong>/rdd 15 -2</strong> effectue un jet 15 à -2
<br><strong>/rdd 15 0 s</strong> effectue un jet 15 à 0, avec significative requise
<br><strong>/rdd Vue Vigilance -2</strong> effectue un jet de Vue/Vigilance à -2 pour les tokens sélectionnés
<br><strong>/rdd vol déser +2</strong> effectue un jet de Volonté/Survie en désert à +2 pour les tokens sélectionnés
<br><strong>/rdd vol déser +2</strong> effectue un jet de Volonté/Survie en Désert à +2 pour les tokens sélectionnés
`
});
this.registerCommand({
@@ -136,7 +137,7 @@ export class RdDCommands {
<br><strong>/jet Vue</strong> poste une demande de jet de VUE à 0
<br><strong>/jet Vue -2</strong> poste une demande de jet de VUE à -2
<br><strong>/jet Vue Vigilance -2</strong> poste une demande de jet de VUE / Vigilance à -2
<br><strong>/jet vol déser +2</strong> poste une demande de jet de VOLONTÉ / Survie en désert à +2
<br><strong>/jet vol déser +2</strong> poste une demande de jet de VOLONTÉ / Survie en Désert à +2
`
});
this.registerCommand({ path: ["/ddr"], func: (content, msg, params) => this.rollDeDraconique(msg), descr: "Lance un Dé Draconique" });
@@ -460,12 +461,7 @@ export class RdDCommands {
async supprimerSignesDraconiquesEphemeres() {
if (game.user.isGM) {
game.actors.forEach(actor => {
const ephemeres = actor.items.filter(item => item.type = 'signedraconique' && item.system.ephemere);
if (ephemeres.length > 0) {
actor.deleteEmbeddedDocuments("Item", ephemeres.map(item => item.id));
}
});
game.actors.forEach(actor => actor.supprimerSignesDraconiques(it => it.system.ephemere))
}
else {
ui.notifications.warn("Seul le MJ est autorisé à utiliser la commande /signe");
+154 -58
View File
@@ -1,10 +1,11 @@
/* -------------------------------------------- */
import { RdDRoll } from "./rdd-roll.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { ChatUtility } from "./chat-utility.js";
import { STATUSES } from "./settings/status-effects.js";
import { ITEM_TYPES } from "./constants.js";
import { ITEM_TYPES, renderTemplate } from "./constants.js";
import { ChatUtility } from "./chat-utility.js";
import { RdDRollResult } from "./rdd-roll-result.js";
import { RdDRoll } from "./rdd-roll.js";
import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs";
import { MAP_PHASE } from "./initiative.mjs";
import { RdDCombatManager } from "./rdd-combat.js";
/* -------------------------------------------- */
export class RdDEmpoignade {
@@ -13,6 +14,58 @@ export class RdDEmpoignade {
static init() {
}
/* -------------------------------------------- */
static isCombatantEmpoignade(actorId, tokenId) {
const combatant = RdDCombatManager.getCombatant(actorId, tokenId)
return MAP_PHASE.empoignade.rang == combatant?.system.init?.rang
}
static async ajustementEmpoignade(attacker, defender, adjust = 1) {
let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
if (empoignade?.system.empoigneurid == defender.id) {
let empoignade = RdDEmpoignade.getEmpoignade(defender, attacker)
return await RdDEmpoignade.$ajustementEmpoignade(empoignade, defender, attacker, - adjust);
}
return await RdDEmpoignade.$ajustementEmpoignade(empoignade, attacker, defender, adjust);
}
static async $ajustementEmpoignade(empoignade, attacker, defender, adjust) {
const empId = empoignade?.system.empoignadeid ?? foundry.utils.randomID(16);
const empFin = (empoignade?.system.pointsemp ?? 0) + adjust
if (empoignade) {
empoignade.system.pointsemp = empFin;
await RdDEmpoignade.$updateEtatEmpoignade(empoignade, attacker, defender);
}
else {
await RdDEmpoignade.$createEtatEmpoignade({
name: `Empoignade de ${attacker.name} sur ${defender.name}`,
type: ITEM_TYPES.empoignade,
system: {
description: "",
empoignadeid: empId,
empoigneurid: attacker.id,
empoigneid: defender.id,
pointsemp: empFin,
empoigneurname: attacker.name,
empoignename: defender.name
}
}, attacker, defender);
}
if (adjust != 0 && empFin == 2) {
await RdDEmpoignade.proposerEntrainerAuSol(attacker, defender, empoignade);
}
const result = RdDEmpoignade.getEmpoignadeById(defender, empId);
const defGrappled = result.system.pointsemp == (result.system.empoigneid == defender.id ? 2 : -2);
const attGrappled = result.system.pointsemp == (result.system.empoigneurid == attacker.id ? -2 : 2);
const grappling = Math.abs(result.system.pointsemp) > 0;
await defender.setEffect(STATUSES.StatusGrappling, grappling && !defGrappled);
await attacker.setEffect(STATUSES.StatusGrappling, grappling && !attGrappled);
await defender.setEffect(STATUSES.StatusGrappled, defGrappled);
await attacker.setEffect(STATUSES.StatusGrappled, attGrappled);
return result
}
/* -------------------------------------------- */
static registerChatCallbacks(html) {
$(html).on("click", '.defense-empoignade-cac', event => {
@@ -49,7 +102,7 @@ export class RdDEmpoignade {
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
if (event.currentTarget.value && event.currentTarget.value != "none") {
RdDEmpoignade.perteEndurance(rollData, event.currentTarget.value)
ChatUtility.removeChatMessageId(chatMessage.id)
//ChatUtility.removeChatMessageId(chatMessage.id)
}
});
}
@@ -94,8 +147,7 @@ export class RdDEmpoignade {
/* -------------------------------------------- */
static getEmpoignadeById(actor, id) {
let emp = actor.itemTypes[ITEM_TYPES.empoignade].find(it => it.system.empoignadeid == id)
return emp && foundry.utils.duplicate(emp) || undefined;
return actor.itemTypes[ITEM_TYPES.empoignade].find(it => it.system.empoignadeid == id)
}
/* -------------------------------------------- */
@@ -185,16 +237,28 @@ export class RdDEmpoignade {
selectedCarac: attacker.system.carac.melee,
malusTaille: RdDEmpoignade.getMalusTaille(empoignade, attacker, defender)
}
if (attacker.isCreatureEntite()) {
RdDItemCompetenceCreature.setRollDataCreature(rollData)
if (attacker.isCreatureOuEntite()) {
MappingCreatureArme.setRollDataCreature(rollData)
}
if (empoignade.system.pointsemp >= 2) {
if (!empoignade.system.ausol) {
let msg = await RdDRollResult.displayRollData(rollData, attacker, 'chat-empoignade-entrainer.hbs');
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
}
await RdDEmpoignade.proposerEntrainerAuSol(attacker, defender, empoignade)
} else {
await RdDEmpoignade.$rollAttaqueEmpoignade(attacker, rollData, isNouvelle);
await RdDEmpoignade.$rollAttaqueEmpoignade(attacker, rollData, isNouvelle)
}
}
static async proposerEntrainerAuSol(attacker, defender, empoignade) {
if (!empoignade.system.ausol) {
const mode = (empoignade && empoignade.system.empoigneurid == attacker.id) ? "empoigner" : "liberer"
const rollData = {
mode, empoignade, attacker, defender,
isEmpoignade: true,
competence: attacker.getCompetenceCorpsACorps(),
selectedCarac: attacker.system.carac.melee,
malusTaille: RdDEmpoignade.getMalusTaille(empoignade, attacker, defender)
}
const msg = await RdDRollResult.displayRollData(rollData, attacker, 'chat-empoignade-entrainer.hbs');
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
}
}
@@ -205,7 +269,14 @@ export class RdDEmpoignade {
await this.onAttaqueEmpoignadeValidee(attacker, defender)
}
static async onImmobilisation(attacker, defender, empoignade) {
static async onImmobilisation(attacker, empoignade) {
const defender = game.actors.get(empoignade.system.empoigneid)
const empDefenseur = defender.itemTypes[ITEM_TYPES.empoignade]
.find(it => it.system.empoignadeid == empoignade.system.empoignadeid);
await defender.updateEmbeddedDocuments('Item', [{
_id: empDefenseur.id,
'system.immobilise': true
}])
const rollData = {
mode: "immobilise",
empoignade, attacker, defender,
@@ -238,10 +309,7 @@ export class RdDEmpoignade {
if (rollData.rolled.isSuccess && isNouvelle) {
const objectEmpoignade = rollData.empoignade.toObject();
// Creer l'empoignade sur attaquant/defenseur
attacker.creerObjetParMJ(objectEmpoignade);
defender.creerObjetParMJ(objectEmpoignade);
RdDEmpoignade.$createEtatEmpoignade(rollData.empoignade)
}
rollData.empoignade.isSuccess = rollData.rolled.isSuccess;
@@ -260,7 +328,7 @@ export class RdDEmpoignade {
return
}
let empoignade = this.getEmpoignade(attacker, defender)
let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
if (!empoignade) {
ui.notifications.warn("Une erreur s'est produite : Aucune empoignade trouvée !!")
@@ -318,27 +386,48 @@ export class RdDEmpoignade {
}
/* -------------------------------------------- */
static async $updateEtatEmpoignade(empoignade) {
console.log("UPDATE Empoignade", empoignade)
static async $createEtatEmpoignade(empoignade) {
console.log("CREATE Empoignade", empoignade)
let defender = game.actors.get(empoignade.system.empoigneid)
let emp = RdDEmpoignade.getEmpoignadeById(defender, empoignade.system.empoignadeid)
let update = { _id: emp._id, "system.pointsemp": empoignade.system.pointsemp, "system.ausol": empoignade.system.ausol }
await defender.updateEmbeddedDocuments('Item', [update])
let attacker = game.actors.get(empoignade.system.empoigneurid)
emp = RdDEmpoignade.getEmpoignadeById(attacker, empoignade.system.empoignadeid)
update = { _id: emp._id, "system.pointsemp": empoignade.system.pointsemp, "system.ausol": empoignade.system.ausol }
await attacker.updateEmbeddedDocuments('Item', [update])
// Creer l'empoignade sur attaquant/defenseur
await attacker.creerObjetParMJ(empoignade)
await defender.creerObjetParMJ(empoignade)
}
/* -------------------------------------------- */
static async $updateEtatEmpoignade(empoignade, attacker, defender) {
const belligerants = [
attacker ?? game.actors.get(empoignade.system.empoigneurid),
defender ?? game.actors.get(empoignade.system.empoigneid)]
const removeEmp = empoignade.system.pointsemp == 0
if (removeEmp) {
const emp = RdDEmpoignade.getEmpoignadeById(attacker, empoignade.system.empoignadeid)
return await attacker.deleteEmbeddedDocuments('Item', [emp.id])
}
else {
await Promise.all(
belligerants.map(async belligerant => {
const emp = RdDEmpoignade.getEmpoignadeById(belligerant, empoignade.system.empoignadeid)
return await belligerant.updateEmbeddedDocuments('Item', [{
_id: emp.id,
"system.pointsemp": empoignade.system.pointsemp,
"system.ausol": empoignade.system.ausol
}])
}))
}
}
/* -------------------------------------------- */
static async $deleteEmpoignade(empoignade) {
console.log("DELETE Empoignade", empoignade)
let defender = game.actors.get(empoignade.system.empoigneid)
let emp = RdDEmpoignade.getEmpoignadeById(defender, empoignade.system.empoignadeid)
await defender.deleteEmbeddedDocuments('Item', [emp._id])
const defender = game.actors.get(empoignade.system.empoigneid)
const emp = RdDEmpoignade.getEmpoignadeById(defender, empoignade.system.empoignadeid)
await defender.deleteEmbeddedDocuments('Item', [emp.id])
}
/* -------------------------------------------- */
@@ -348,7 +437,7 @@ export class RdDEmpoignade {
if (!RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
return
}
let empoignade = this.getEmpoignade(attacker, defender)
let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
empoignade.system.ausol = true
await this.$updateEtatEmpoignade(empoignade)
@@ -367,7 +456,7 @@ export class RdDEmpoignade {
if (!RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
return
}
let empoignade = this.getEmpoignade(attacker, defender)
let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
await defender.setEffect(STATUSES.StatusProne, true);
await this.$deleteEmpoignade(empoignade)
@@ -380,29 +469,28 @@ export class RdDEmpoignade {
static async perteEndurance(rollData, perteMode) {
let attacker = game.actors.get(rollData.attacker.id)
let defender = game.actors.get(rollData.defender.id)
if (!RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
if (perteMode == "none" || !RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
return
}
let empoignade = this.getEmpoignade(attacker, defender)
//console.log("Perte d'endurance :!!!", perteMode)
let endValue = defender.system.sante.endurance.value
if (perteMode == "end0") {
await defender.santeIncDec("endurance", -endValue);
}
if (perteMode == "end1") {
await defender.santeIncDec("endurance", -(endValue - 1));
}
if (perteMode == "endmoitie") {
await defender.santeIncDec("endurance", -Math.floor(endValue / 2));
}
if (perteMode == "endquart") {
await defender.santeIncDec("endurance", -(3 * Math.floor(endValue / 4)));
}
let msg = await RdDRollResult.displayRollData(rollData, attacker, 'chat-empoignade-perte-endurance.hbs');
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
const perteEndurance = await RdDEmpoignade.$calcPerteEnd(perteMode, defender.system.sante.endurance.value)
await defender.santeIncDec("endurance", -perteEndurance)
await RdDRollResult.displayRollData({ attacker, defender, perteEndurance },
attacker,
'chat-empoignade-perte-endurance.hbs')
}
static async $calcPerteEnd(perteMode, endValue) {
switch (perteMode) {
case "none": return 0
case "end0": return endValue
case "end1": return (endValue - 1)
case "3/4": return Math.floor(3 * endValue / 4)
case "1/2": return Math.floor(endValue / 2)
case "1/4": return Math.floor(endValue / 4)
}
const rolled = await (new Roll(perteMode).evaluate())
return rolled.total
}
/* -------------------------------------------- */
static async deleteAllEmpoignades() {
for (let actor of game.actors) {
@@ -417,16 +505,24 @@ export class RdDEmpoignade {
let actor = game.actors.get(actorDeleteId)
let emp = this.getEmpoignadeById(actor, empoignade.system.empoignadeid)
if (emp) {
await actor.deleteEmbeddedDocuments('Item', [emp._id])
await actor.deleteEmbeddedDocuments('Item', [emp.id])
}
}
/* -------------------------------------------- */
static async createEmpoignade(attacker, defender) {
return await Item.create({
name: "Empoignade en cours de " + attacker.name + ' sur ' + defender.name,
type: 'empoignade',
system: { description: "", empoignadeid: foundry.utils.randomID(16), compteempoigne: 0, empoigneurid: attacker.id, empoigneid: defender.id, ptsemp: 0, empoigneurname: attacker.name, empoignename: defender.name }
name: "Empoignade de " + attacker.name + ' sur ' + defender.name,
type: ITEM_TYPES.empoignade,
system: {
description: "",
empoignadeid: foundry.utils.randomID(16),
empoigneurid: attacker.id,
empoigneid: defender.id,
pointsemp: 0,
empoigneurname: attacker.name,
empoignename: defender.name
}
},
{
temporary: true
+21 -19
View File
@@ -1,5 +1,4 @@
import { RdDItemArme } from "./item/arme.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { ATTAQUE_TYPE, EMPOIGNADE, PUGILAT, RdDItemArme } from "./item/arme.js";
import { ITEM_TYPES } from "./constants.js";
export class RdDHotbar {
@@ -20,14 +19,17 @@ export class RdDHotbar {
await game.user.assignHotbarMacro(macro, slot);
}
static $macroNameSuffix(armeCompetence) {
switch (armeCompetence) {
case '(1 main)': return ' (1 main)';
case '(2 mains)': return ' (2 main)';
static $macroNameSuffix(maniement) {
switch (maniement) {
case ATTAQUE_TYPE.UNE_MAIN:
case ATTAQUE_TYPE.DEUX_MAINS:
case ATTAQUE_TYPE.LANCER:
case ATTAQUE_TYPE.TIR:
return ' ' + maniement
case 'tir': return ' (tir)';
case 'lancer': return ' (lancer)';
case 'pugilat': return ' (pugilat)';
case 'empoignade': return ' (empoignade)';
case PUGILAT: return ' (pugilat)';
case EMPOIGNADE: return ' (empoignade)';
}
return ''
}
@@ -39,30 +41,30 @@ export class RdDHotbar {
// Les armes peuvent avoir plusieurs usages
if (item.system.competence != '') {
if (item.system.unemain) {
await this.createItemMacro(item, slot++, '(1 main)')
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.UNE_MAIN)
}
if (item.system.deuxmains) {
await this.createItemMacro(item, slot++, '(2 mains)')
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.DEUX_MAINS)
}
}
if (item.system.lancer != '') {
await this.createItemMacro(item, slot++, 'lancer')
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.LANCER)
}
if (item.system.tir != '') {
await this.createItemMacro(item, slot++, 'lancer')
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.TIR)
}
}
return
case ITEM_TYPES.competencecreature:
const categorie = RdDItemCompetenceCreature.getCategorieAttaque(item) ?? 'competence';
const categorie = item.getCategorieAttaque() ?? 'competence';
await this.createItemMacro(item, slot, categorie)
return
default:
case ITEM_TYPES.competence:
await this.createItemMacro(item, slot++, 'competence')
if (item.isCorpsACorps()) {
await this.createItemMacro(item, slot++, 'pugilat')
await this.createItemMacro(item, slot++, 'empoignade')
await this.createItemMacro(item, slot++, PUGILAT)
await this.createItemMacro(item, slot++, EMPOIGNADE)
}
else if (item.isCompetenceArme()) {
ui.notifications.info(`${item.name} est une compétence d'arme, la macro n'est pas liée à un arme.<br>
@@ -119,15 +121,15 @@ export class RdDHotbar {
case ITEM_TYPES.competence:
if (item.isCorpsACorps()) {
switch (categorieArme) {
case 'pugilat':
return actor.rollArme(RdDItemArme.corpsACorps(actor));
case 'empoignade':
case PUGILAT:
return actor.rollArme(RdDItemArme.pugilat(actor));
case EMPOIGNADE:
return actor.rollArme(RdDItemArme.empoignade(actor));
}
}
return actor.rollCompetence(item);
case ITEM_TYPES.competencecreature:
return item.system.iscombat && !item.system.isparade
return item.system.iscombat
? actor.rollArme(item, categorieArme)
: actor.rollCompetence(item);
+21 -13
View File
@@ -45,6 +45,8 @@ import * as sheets from "./applications/sheets/_module.mjs"
import { RdDItemArme } from "./item/arme.js"
import { RdDItemArmure } from "./item/armure.js"
import { RdDItemBlessure } from "./item/blessure.js"
import { RdDItemCompetence } from "./item-competence.js"
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"
import { RdDItemGemme } from "./item/gemme.js"
import { RdDItemMaladie } from "./item/maladie.js"
import { RdDItemOmbre } from "./item/ombre.js"
@@ -86,6 +88,8 @@ import { RdDCombatManager, RdDCombat } from "./rdd-combat.js"
import { Migrations } from './migrations.js'
import RollDialog from "./roll/roll-dialog.mjs"
import ChatRollResult from "./roll/chat-roll-result.mjs"
import ExportPdf from "./actor/export-pdf/export-pdf.mjs"
/**
* RdD system
@@ -112,6 +116,8 @@ export class SystemReveDeDragon {
arme: RdDItemArme,
armure: RdDItemArmure,
blessure: RdDItemBlessure,
competence: RdDItemCompetence,
competencecreature: RdDItemCompetenceCreature,
gemme: RdDItemGemme,
maladie: RdDItemMaladie,
ombre: RdDItemOmbre,
@@ -291,7 +297,9 @@ export class SystemReveDeDragon {
RdDPossession.init()
TMRRencontres.init()
ExportScriptarium.init()
ExportPdf.init()
RollDialog.init()
ChatRollResult.init()
}
initSettings() {
@@ -346,18 +354,7 @@ export class SystemReveDeDragon {
})
}
static async setupAccueil() {
let exists = game.scenes.find(j => j.name == "Accueil RdD");
if (!exists) {
const scenes = await SystemCompendiums.loadCompendium("foundryvtt-reve-de-dragon.scenes-rdd")
let newDocuments = scenes.filter(i => i.name == "Accueil RdD");
await game.scenes.documentClass.create(newDocuments);
game.scenes.find(i => i.name == "Accueil RdD").activate();
}
}
async onReady() {
/* -------------------------------------------- */
/* Foundry VTT Initialization */
/* -------------------------------------------- */
@@ -376,7 +373,8 @@ export class SystemReveDeDragon {
StatusEffects.onReady()
RdDDice.onReady()
RollDialog.onReady()
RdDStatBlockParser.parseStatBlock()
ChatRollResult.onReady()
/* -------------------------------------------- */
/* Affiche/Init le calendrier */
game.system.rdd.calendrier.display()
@@ -389,7 +387,17 @@ export class SystemReveDeDragon {
})
}
SystemReveDeDragon.setupAccueil()
this.setupAccueil()
}
async setupAccueil() {
let exists = game.scenes.find(j => j.name == "Accueil RdD");
if (!exists) {
const scenes = await SystemCompendiums.loadCompendium("foundryvtt-reve-de-dragon.scenes-rdd")
let newDocuments = scenes.filter(i => i.name == "Accueil RdD");
await game.scenes.documentClass.create(newDocuments);
game.scenes.find(i => i.name == "Accueil RdD").activate();
}
}
/* -------------------------------------------- */
+1
View File
@@ -1,4 +1,5 @@
import { ChatUtility } from "./chat-utility.js"
import { renderTemplate } from "./constants.js"
const vents = [
{ min: 0, max: 0, valeur: 'Calme' },
+1
View File
@@ -1,5 +1,6 @@
import { RdDBaseActor } from "./actor/base-actor.js";
import { ChatUtility } from "./chat-utility.js";
import { renderTemplate } from "./constants.js";
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";

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