Compare commits
12 Commits
2cbee42180
...
13.0.16
| Author | SHA1 | Date | |
|---|---|---|---|
| 0d62b60e38 | |||
| 9b91850731 | |||
| 05c7a91f93 | |||
| f83fdb3b8f | |||
| 020ff4b014 | |||
| b3c7453823 | |||
| 18d003aa5d | |||
| 0b90badb5e | |||
| 290b5029d1 | |||
| a7e4aea52d | |||
| 755d15509e | |||
| 02cea84ebb |
@@ -25,4 +25,7 @@ Merci à eux !!
|
||||
|
||||
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
assets/actions/empoignade.svg
Normal file
1
assets/actions/empoignade.svg
Normal 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 |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
65
assets/actions/surenc.svg
Normal file
65
assets/actions/surenc.svg
Normal 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 |
BIN
assets/feuille-personnage.pdf
Normal file
BIN
assets/feuille-personnage.pdf
Normal file
Binary file not shown.
28
changelog.md
28
changelog.md
@@ -1,15 +1,41 @@
|
||||
# 13.0
|
||||
## 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
|
||||
- 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
|
||||
|
||||
|
||||
@@ -648,15 +648,19 @@ select,
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="coeur"] select[name="coeur"] {
|
||||
max-width: 4rem;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="tricher"] img {
|
||||
/* image de d100 */
|
||||
max-width: 2.5rem;
|
||||
max-height: 2.5rem;
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section img {
|
||||
max-width: 1rem;
|
||||
max-height: 1rem;
|
||||
gap: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
filter: invert(0.8);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="tricher"] img {
|
||||
/* image de d100 */
|
||||
max-width: 2.5rem;
|
||||
max-height: 2.5rem;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-buttons {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
@@ -1374,6 +1378,9 @@ select,
|
||||
margin: 0.1rem 0;
|
||||
align-items: center;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .prosemirror menu {
|
||||
background-color: var(--color-background-chat-message);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .app.sheet .editor.prosemirror {
|
||||
height: fit-content;
|
||||
min-height: 5rem;
|
||||
@@ -1565,22 +1572,70 @@ select,
|
||||
.system-foundryvtt-reve-de-dragon .type-compendium {
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-header {
|
||||
background: #011d33 url(../assets/ui/bg_header.webp) no-repeat left top;
|
||||
color: #ffffff;
|
||||
.system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-body,
|
||||
.system-foundryvtt-reve-de-dragon .application .window-content,
|
||||
.system-foundryvtt-reve-de-dragon .journal-entry .journal-sidebar {
|
||||
background: url(../assets/ui/bg_left.webp) no-repeat left top;
|
||||
color: var(--rdd-color-text-primary);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-header :is(
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="password"],
|
||||
input[type="datetime-local"],
|
||||
input[type="date"],
|
||||
input[type="time"]) {
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
.system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-body label,
|
||||
.system-foundryvtt-reve-de-dragon .application .window-content label,
|
||||
.system-foundryvtt-reve-de-dragon .journal-entry .journal-sidebar label,
|
||||
.system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-body .hint,
|
||||
.system-foundryvtt-reve-de-dragon .application .window-content .hint,
|
||||
.system-foundryvtt-reve-de-dragon .journal-entry .journal-sidebar .hint,
|
||||
.system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-body .permissions-list,
|
||||
.system-foundryvtt-reve-de-dragon .application .window-content .permissions-list,
|
||||
.system-foundryvtt-reve-de-dragon .journal-entry .journal-sidebar .permissions-list,
|
||||
.system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-body nav.tabs,
|
||||
.system-foundryvtt-reve-de-dragon .application .window-content nav.tabs,
|
||||
.system-foundryvtt-reve-de-dragon .journal-entry .journal-sidebar nav.tabs,
|
||||
.system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-body nav.tabs button,
|
||||
.system-foundryvtt-reve-de-dragon .application .window-content nav.tabs button,
|
||||
.system-foundryvtt-reve-de-dragon .journal-entry .journal-sidebar nav.tabs button,
|
||||
.system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-body nav.tabs button .count,
|
||||
.system-foundryvtt-reve-de-dragon .application .window-content nav.tabs button .count,
|
||||
.system-foundryvtt-reve-de-dragon .journal-entry .journal-sidebar nav.tabs button .count,
|
||||
.system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-body button,
|
||||
.system-foundryvtt-reve-de-dragon .application .window-content button,
|
||||
.system-foundryvtt-reve-de-dragon .journal-entry .journal-sidebar button {
|
||||
color: var(--rdd-color-text-primary);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-body a,
|
||||
.system-foundryvtt-reve-de-dragon .application .window-content a,
|
||||
.system-foundryvtt-reve-de-dragon .journal-entry .journal-sidebar a {
|
||||
color: var(--color-dark-3);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-body a.filter.active,
|
||||
.system-foundryvtt-reve-de-dragon .application .window-content a.filter.active,
|
||||
.system-foundryvtt-reve-de-dragon .journal-entry .journal-sidebar a.filter.active {
|
||||
color: var(--color-dark-1);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .window-app .window-content {
|
||||
background: url(../assets/ui/bg_left.webp) no-repeat left top;
|
||||
color: var(--rdd-color-text-primary);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .window-app .window-content .sheet-header {
|
||||
background: #011d33 url(../assets/ui/bg_header.webp) no-repeat left top;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .window-app .window-content .sheet-header label,
|
||||
.system-foundryvtt-reve-de-dragon .window-app .window-content .sheet-header .hint,
|
||||
.system-foundryvtt-reve-de-dragon .window-app .window-content .sheet-header .permissions-list,
|
||||
.system-foundryvtt-reve-de-dragon .window-app .window-content .sheet-header nav.tabs,
|
||||
.system-foundryvtt-reve-de-dragon .window-app .window-content .sheet-header nav.tabs button,
|
||||
.system-foundryvtt-reve-de-dragon .window-app .window-content .sheet-header nav.tabs button .count,
|
||||
.system-foundryvtt-reve-de-dragon .window-app .window-content .sheet-header div,
|
||||
.system-foundryvtt-reve-de-dragon .window-app .window-content .sheet-header button {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .window-app .window-content .sheet-header input {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
border: 0 none;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .window-app .window-content .sheet-header input[type="checkbox"] {
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon input[type="number"] {
|
||||
text-align: right;
|
||||
padding-right: 0.5rem;
|
||||
@@ -1621,7 +1676,7 @@ select,
|
||||
width: calc(100% - 2px);
|
||||
height: var(--form-field-height);
|
||||
margin: 0;
|
||||
color: var(--color-text-dark-primary);
|
||||
color: var(--rdd-color-text-primary);
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon form.app-personnage-aleatoire h2 {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"TYPES": {
|
||||
"Actor": {
|
||||
"Actor": {
|
||||
"personnage": "Personnage",
|
||||
"creature": "Créature",
|
||||
"entite": "Entité de cauchemar",
|
||||
@@ -67,6 +67,7 @@
|
||||
"StatusComma": "Comma",
|
||||
"StatusDead": "Mort",
|
||||
"StatusDemiReve": "Demi-rêve",
|
||||
"StatusSurEnc": "Sur-encombrement",
|
||||
"StatusForceWeak": "Force insuffisante"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,9 +656,15 @@
|
||||
margin: 0.1rem 0;
|
||||
align-items: center;
|
||||
}
|
||||
.prosemirror {
|
||||
menu{
|
||||
background-color: var(--color-background-chat-message);
|
||||
}
|
||||
}
|
||||
.app.sheet .editor.prosemirror {
|
||||
height: fit-content;
|
||||
min-height: 5rem;
|
||||
|
||||
}
|
||||
.app.sheet .editor.prosemirror .editor-container {
|
||||
min-height: 5rem;
|
||||
@@ -865,26 +871,60 @@
|
||||
.type-compendium {
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
|
||||
.window-app.sheet .window-content .sheet-body,
|
||||
.application .window-content,
|
||||
.journal-entry .journal-sidebar {
|
||||
background: url(../assets/ui/bg_left.webp) no-repeat left top;
|
||||
color: var(--rdd-color-text-primary);
|
||||
label ,
|
||||
.hint ,
|
||||
.permissions-list ,
|
||||
nav.tabs,
|
||||
nav.tabs button,
|
||||
nav.tabs button .count,
|
||||
button {
|
||||
color: var(--rdd-color-text-primary);
|
||||
}
|
||||
a {
|
||||
color: var(--color-dark-3);
|
||||
}
|
||||
a.filter.active {
|
||||
color: var(--color-dark-1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ======================================== */
|
||||
/* Sheet */
|
||||
.window-app.sheet .window-content .sheet-header{
|
||||
background: #011d33 url(../assets/ui/bg_header.webp) no-repeat left top;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
.window-app .window-content{
|
||||
background: url(../assets/ui/bg_left.webp) no-repeat left top;
|
||||
color: var(--rdd-color-text-primary);
|
||||
|
||||
.sheet-header {
|
||||
background: #011d33 url(../assets/ui/bg_header.webp) no-repeat left top;
|
||||
|
||||
label ,
|
||||
.hint ,
|
||||
.permissions-list ,
|
||||
nav.tabs,
|
||||
nav.tabs button,
|
||||
nav.tabs button .count,
|
||||
div,
|
||||
button {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
input {
|
||||
//color: rgba(255, 255, 255, 0);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
border: 0 none;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
input[type="checkbox"] {
|
||||
// background-color: hsla(268, 41%, 56%, 0.9);
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.window-app.sheet .window-content .sheet-header :is(
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="password"],
|
||||
input[type="datetime-local"],
|
||||
input[type="date"],
|
||||
input[type="time"]) {
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 0 none;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
input[type="number"] {
|
||||
text-align: right;
|
||||
@@ -928,7 +968,7 @@
|
||||
width: calc(100% - 2px);
|
||||
height: var(--form-field-height);
|
||||
margin: 0;
|
||||
color: var(--color-text-dark-primary);
|
||||
color: var(--rdd-color-text-primary);
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
form.app-personnage-aleatoire {
|
||||
|
||||
@@ -224,15 +224,19 @@
|
||||
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;
|
||||
|
||||
@@ -375,14 +375,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);
|
||||
|
||||
@@ -185,12 +185,12 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
const actions = []
|
||||
const uniques = []
|
||||
|
||||
const addAttaque = (arme, main = undefined, action = 'attaque') => {
|
||||
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;
|
||||
|
||||
const comp = this.getCompetence(RdDActor.$getCompetenceAction(arme, main))
|
||||
const comp = this.getCompetence(arme.getCompetenceAction(main))
|
||||
const unique = [comp.id, arme.name, dommages, forceRequise, ecaillesEfficacite].join('|');
|
||||
if (uniques.includes(unique)) {
|
||||
return
|
||||
@@ -218,18 +218,14 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
})
|
||||
}
|
||||
|
||||
addAttaque(RdDItemArme.empoignade(this), ATTAQUE_TYPE.CORPS_A_CORPS)
|
||||
|
||||
this.itemTypes[ITEM_TYPES.arme]
|
||||
.filter(it => it.isAttaque())
|
||||
.sort(Misc.ascending(it => it.name))
|
||||
.forEach(arme => {
|
||||
if (arme.system.unemain && arme.system.competence && arme.system.resistance > 0) { addAttaque(arme, ATTAQUE_TYPE.UNE_MAIN) }
|
||||
if (arme.system.deuxmains && arme.system.competence && arme.system.resistance > 0) { addAttaque(arme, ATTAQUE_TYPE.DEUX_MAINS) }
|
||||
if (arme.system.lancer && arme.system.resistance > 0) { addAttaque(arme, ATTAQUE_TYPE.LANCER) }
|
||||
if (arme.system.tir) { addAttaque(arme, ATTAQUE_TYPE.TIR) }
|
||||
})
|
||||
.forEach(arme => arme.getTypeAttaques().forEach(t => addAttaque(arme, t)))
|
||||
|
||||
addAttaque(RdDItemArme.pugilat(this), ATTAQUE_TYPE.CORPS_A_CORPS)
|
||||
addAttaque(RdDItemArme.empoignade(this), ATTAQUE_TYPE.CORPS_A_CORPS, 'empoignade')
|
||||
|
||||
return actions
|
||||
}
|
||||
@@ -245,16 +241,6 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
}
|
||||
|
||||
static $getCompetenceAction(arme, main) {
|
||||
switch (main) {
|
||||
case ATTAQUE_TYPE.UNE_MAIN: return arme.competence1Mains()
|
||||
case ATTAQUE_TYPE.DEUX_MAINS: return arme.competence2Mains()
|
||||
case ATTAQUE_TYPE.LANCER: return arme.system.lancer
|
||||
case ATTAQUE_TYPE.TIR: return arme.system.tir
|
||||
default: return arme.system.competence
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async $perteReveEnchantementsChateauDormants() {
|
||||
const toUpdate = this.items.filter(it => [ITEM_TYPES.potion, ITEM_TYPES.gemme].includes(it.type))
|
||||
@@ -756,20 +742,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);
|
||||
}
|
||||
|
||||
@@ -1754,7 +1738,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
this.tmrApp?.close();
|
||||
this.tmrApp = undefined;
|
||||
}
|
||||
} ],
|
||||
}],
|
||||
onRollDone: RollDialog.onRollDoneClose,
|
||||
onClose: () => {
|
||||
this.tmrApp?.restoreTMRAfterAction();
|
||||
@@ -2608,7 +2592,7 @@ 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);
|
||||
}
|
||||
@@ -2999,6 +2983,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
if (updatedEndurance && options.diff) {
|
||||
await this.setEffect(STATUSES.StatusUnconscious, updatedEndurance.value == 0)
|
||||
}
|
||||
await super.onUpdateActor(update, options, actorId)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -3041,9 +3026,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)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
@@ -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))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,6 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
getSConst() { return 0 }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
isSurenc() { return false }
|
||||
computeMalusSurEncombrement() { return 0 }
|
||||
|
||||
ajustementAstrologique() { return 0 }
|
||||
@@ -126,6 +125,8 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
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 }) {
|
||||
@@ -204,6 +205,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
getPossession(possessionId) {
|
||||
return this.itemTypes[ITEM_TYPES.possession].find(it => it.system.possessionid == possessionId);
|
||||
}
|
||||
|
||||
getEmpoignades() {
|
||||
return this.itemTypes[ITEM_TYPES.empoignade];
|
||||
}
|
||||
@@ -227,49 +229,9 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
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
|
||||
}
|
||||
|
||||
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], { render: true })
|
||||
}
|
||||
if (status && !effect) {
|
||||
await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(statusId)], { render: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async removeEffect(id) {
|
||||
this.removeEffects(it => it.id == id)
|
||||
}
|
||||
|
||||
async removeEffects(filter = e => true) {
|
||||
if (game.user.isGM) {
|
||||
const effectsToRemove = this.getEffects(filter);
|
||||
const ids = effectsToRemove.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, forceRequise = undefined) {
|
||||
|
||||
@@ -186,6 +186,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
await this.changeBleedingState()
|
||||
break
|
||||
}
|
||||
await super.onCreateItem(item, options, id)
|
||||
}
|
||||
|
||||
async onUpdateItem(item, options, id) {
|
||||
@@ -194,6 +195,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
await this.changeBleedingState()
|
||||
break
|
||||
}
|
||||
await super.onUpdateItem(item, options, id)
|
||||
}
|
||||
|
||||
async changeBleedingState() {
|
||||
@@ -313,7 +315,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
}
|
||||
|
||||
isSonne() {
|
||||
return this.getEffectByStatus(STATUSES.StatusStunned)
|
||||
return this.getEffectsByStatus(STATUSES.StatusStunned).length > 0
|
||||
}
|
||||
|
||||
isEffectAllowed(effectId) { return true }
|
||||
|
||||
@@ -49,7 +49,7 @@ 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);
|
||||
@@ -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);
|
||||
|
||||
@@ -10,7 +10,7 @@ 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 { STATUSES } from "../settings/status-effects.js";
|
||||
import { StatusEffects, STATUSES } from "../settings/status-effects.js";
|
||||
|
||||
export class RdDBaseActor extends Actor {
|
||||
|
||||
@@ -243,18 +243,68 @@ 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 effectsToRemove = this.getEffects(filter);
|
||||
const ids = effectsToRemove.map(it => it.id);
|
||||
await this.deleteEmbeddedDocuments('ActiveEffect', ids);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
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 onCreateItem(item, options, id) {
|
||||
}
|
||||
|
||||
async onUpdateItem(item, options, id) { }
|
||||
|
||||
async onUpdateActor(update, options, actorId) { }
|
||||
async onUpdateItem(item, options, id) {
|
||||
}
|
||||
|
||||
async onDeleteItem(item, options, id) {
|
||||
if (item.isInventaire()) {
|
||||
@@ -262,6 +312,7 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async _removeItemFromConteneur(item) {
|
||||
const updates = this.items.filter(it => it.isConteneur() && it.system.contenu.includes(item.id))
|
||||
.map(conteneur => {
|
||||
@@ -510,16 +561,22 @@ export class RdDBaseActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async computeEncTotal() {
|
||||
if (!this.pack) {
|
||||
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)
|
||||
return this.encTotal;
|
||||
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) {
|
||||
@@ -570,7 +627,7 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
}
|
||||
}
|
||||
await this.computeEncTotal();
|
||||
await this.computeEncTotal()
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
module/actor/export-pdf/export-pdf.mjs
Normal file
288
module/actor/export-pdf/export-pdf.mjs
Normal 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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
39404
module/actor/export-pdf/pdf-lib/pdf-lib.esm.js
Normal file
39404
module/actor/export-pdf/pdf-lib/pdf-lib.esm.js
Normal file
File diff suppressed because one or more lines are too long
1
module/actor/export-pdf/pdf-lib/pdf-lib.esm.js.map
Normal file
1
module/actor/export-pdf/pdf-lib/pdf-lib.esm.js.map
Normal file
File diff suppressed because one or more lines are too long
16
module/actor/export-pdf/pdf-lib/pdf-lib.esm.min.js
vendored
Normal file
16
module/actor/export-pdf/pdf-lib/pdf-lib.esm.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
module/actor/export-pdf/pdf-lib/pdf-lib.esm.min.js.map
Normal file
1
module/actor/export-pdf/pdf-lib/pdf-lib.esm.min.js.map
Normal file
File diff suppressed because one or more lines are too long
39674
module/actor/export-pdf/pdf-lib/pdf-lib.js
Normal file
39674
module/actor/export-pdf/pdf-lib/pdf-lib.js
Normal file
File diff suppressed because one or more lines are too long
1
module/actor/export-pdf/pdf-lib/pdf-lib.js.map
Normal file
1
module/actor/export-pdf/pdf-lib/pdf-lib.js.map
Normal file
File diff suppressed because one or more lines are too long
16
module/actor/export-pdf/pdf-lib/pdf-lib.min.js
vendored
Normal file
16
module/actor/export-pdf/pdf-lib/pdf-lib.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
module/actor/export-pdf/pdf-lib/pdf-lib.min.js.map
Normal file
1
module/actor/export-pdf/pdf-lib/pdf-lib.min.js.map
Normal file
File diff suppressed because one or more lines are too long
@@ -60,8 +60,9 @@ export const RDD_CONFIG = {
|
||||
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/icons/empoignade.webp',
|
||||
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',
|
||||
},
|
||||
encaissement: {
|
||||
mortel: 'mortel',
|
||||
|
||||
@@ -20,11 +20,11 @@ export class RdDInitiative {
|
||||
return "1d6" + (base >= 0 ? "+" : "") + base
|
||||
}
|
||||
|
||||
static ajustementInitiative(caracValue, niveau, bonus) {
|
||||
static ajustementInitiative(caracValue, niveau, bonus = 0) {
|
||||
return niveau + Math.floor(caracValue / 2) + bonus
|
||||
}
|
||||
|
||||
static formule(phase, carac, niveau, bonusMalus) {
|
||||
static formule(phase, carac, niveau, bonusMalus = 0) {
|
||||
const ajustement = RdDInitiative.ajustementInitiative(carac, niveau, bonusMalus)
|
||||
return { phase, ajustement }
|
||||
}
|
||||
@@ -58,6 +58,7 @@ export class RdDInitiative {
|
||||
return {
|
||||
roll: roll,
|
||||
value: value,
|
||||
rang: formule.phase.rang,
|
||||
init: formule.phase.rang + value / 100,
|
||||
label: formule.phase.label
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { RdDInitiative } from "./initiative.mjs";
|
||||
import { RdDItem } from "./item.js";
|
||||
import { CATEGORIES_COMPETENCES, 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"],
|
||||
@@ -46,6 +47,30 @@ export class RdDItemCompetence extends RdDItem {
|
||||
|
||||
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;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -27,6 +27,7 @@ export const ATTAQUE_TYPE = {
|
||||
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'
|
||||
@@ -44,6 +45,16 @@ export class RdDItemArme extends RdDItem {
|
||||
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() ?? ""
|
||||
@@ -77,17 +88,26 @@ export class RdDItemArme extends RdDItem {
|
||||
return arme.name
|
||||
case ITEM_TYPES.arme:
|
||||
switch (maniement) {
|
||||
case ATTAQUE_TYPE.COMPETENCE: return arme.system.competence;
|
||||
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.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);
|
||||
@@ -254,6 +274,14 @@ export class RdDItemArme extends RdDItem {
|
||||
return this.system.resistance > 0 || (this.system.tir != '' && this.system.portee_courte > 0)
|
||||
}
|
||||
|
||||
isEmpoignade() {
|
||||
return this.system.mortalite == RDD_CONFIG.encaissement.empoignade
|
||||
}
|
||||
|
||||
isUtilisableEmpoigne() {
|
||||
return this.system.baseInit == 3 || this.system.baseInit == 4 || this.system.competence == "Dague"
|
||||
}
|
||||
|
||||
static pugilat(actor) {
|
||||
return RdDItemArme.$corpsACorps(actor, 'Pugilat', PUGILAT)
|
||||
}
|
||||
|
||||
@@ -14,27 +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": { 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" }
|
||||
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": { 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" },
|
||||
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" },
|
||||
}
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -74,6 +74,7 @@ export class RdDBonus {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -56,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();
|
||||
@@ -402,7 +408,6 @@ export class RdDCombat {
|
||||
/* -------------------------------------------- */
|
||||
static registerChatCallbacks(html) {
|
||||
for (let button of [
|
||||
'.button-defense',
|
||||
'.button-parade',
|
||||
'.button-esquive',
|
||||
'.button-encaisser',
|
||||
@@ -474,8 +479,6 @@ export class RdDCombat {
|
||||
|
||||
switch (button) {
|
||||
case '.particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value);
|
||||
case '.button-defense': return this.defenseV2(attackerRoll);
|
||||
|
||||
case '.button-parade': return this.parade(attackerRoll, armeParadeId);
|
||||
case '.button-esquive': return this.esquive(attackerRoll, compId, competence);
|
||||
case '.button-encaisser': return this.encaisser(attackerRoll, defenderRoll);
|
||||
@@ -725,24 +728,24 @@ export class RdDCombat {
|
||||
async _chatMessageDefenseV2(paramDemandeDefense) {
|
||||
const attackerRoll = paramDemandeDefense.attackerRoll;
|
||||
RollBasicParts.loadSurprises(attackerRoll)
|
||||
attackerRoll.passeArme = attackerRoll.passeArme ?? foundry.utils.randomID(16)
|
||||
attackerRoll.dmg = RdDBonus.dmgRollV2(attackerRoll, attackerRoll.current.attaque)
|
||||
const attaque = RollDialog.saveParts(attackerRoll)
|
||||
const defense = {
|
||||
attackerRoll: attaque,
|
||||
ids: RollBasicParts.reverseIds(attaque),
|
||||
passeArme: attaque.passeArme ?? foundry.utils.randomID(16)
|
||||
}
|
||||
|
||||
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', attackerRoll)
|
||||
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, 'rollData', defense)
|
||||
ChatUtility.setMessageData(choixDefense, 'demande-defense', true)
|
||||
ChatUtility.setMessageData(choixDefense, 'rollData', {
|
||||
ids: defenseData.ids,
|
||||
attackerRoll: RollDialog.saveParts(attackerRoll),
|
||||
passeArme: defenseData.passeArme
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -1052,7 +1055,7 @@ export class RdDCombat {
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
async defenseV2(attackerRoll) {
|
||||
async defenseV2(attackerRoll, callbacks = []) {
|
||||
// this._prepareParade(attackerRoll, arme, competence);
|
||||
RollDialog.loadRollData(attackerRoll)
|
||||
await this.doRollDefense({
|
||||
@@ -1065,7 +1068,7 @@ export class RdDCombat {
|
||||
type: { allowed: [ROLL_TYPE_DEFENSE], current: ROLL_TYPE_DEFENSE },
|
||||
attackerRoll: attackerRoll,
|
||||
passeArme: attackerRoll.passeArme,
|
||||
})
|
||||
}, callbacks)
|
||||
}
|
||||
|
||||
async doRollDefense(rollData, callbacks = []) {
|
||||
|
||||
@@ -4,6 +4,8 @@ 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 {
|
||||
@@ -12,6 +14,49 @@ 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) {
|
||||
const empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
|
||||
const empId = empoignade?.system.empoignadeid ?? foundry.utils.randomID(16)
|
||||
if (empoignade) {
|
||||
if (empoignade.system.empoigneurid == defender.id) {
|
||||
adjust = - adjust
|
||||
}
|
||||
empoignade.system.pointsemp += adjust
|
||||
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: adjust,
|
||||
empoigneurname: attacker.name,
|
||||
empoignename: defender.name
|
||||
}
|
||||
}, attacker, defender)
|
||||
}
|
||||
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 => {
|
||||
@@ -237,10 +282,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;
|
||||
@@ -259,7 +301,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 !!")
|
||||
@@ -317,18 +359,33 @@ 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) {
|
||||
console.log("UPDATE Empoignade", empoignade)
|
||||
const belligerants = [
|
||||
attacker ?? game.actors.get(empoignade.system.empoigneurid),
|
||||
defender ?? game.actors.get(empoignade.system.empoigneid)]
|
||||
|
||||
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
|
||||
}])
|
||||
}))
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -347,7 +404,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)
|
||||
@@ -366,7 +423,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)
|
||||
@@ -382,7 +439,7 @@ export class RdDEmpoignade {
|
||||
if (!RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
|
||||
return
|
||||
}
|
||||
let empoignade = this.getEmpoignade(attacker, defender)
|
||||
let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
|
||||
|
||||
//console.log("Perte d'endurance :!!!", perteMode)
|
||||
let endValue = defender.system.sante.endurance.value
|
||||
@@ -423,9 +480,17 @@ export class RdDEmpoignade {
|
||||
/* -------------------------------------------- */
|
||||
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
|
||||
|
||||
@@ -89,6 +89,7 @@ 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
|
||||
@@ -296,6 +297,7 @@ export class SystemReveDeDragon {
|
||||
RdDPossession.init()
|
||||
TMRRencontres.init()
|
||||
ExportScriptarium.init()
|
||||
ExportPdf.init()
|
||||
RollDialog.init()
|
||||
ChatRollResult.init()
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ export class RdDRoll extends Dialog {
|
||||
// Mise à jour valeurs
|
||||
this.html.find(".dialog-roll-title").text(this._getTitle(rollData));
|
||||
this.html.find("input.check-mortalite").prop('checked', rollData.dmg.mortalite == RDD_CONFIG.encaissement.nonmortel);
|
||||
this.html.find("label.dmg-arme-actor").text(rollData.dmg.mortalite == EMPOIGNADE ? EMPOIGNADE : Misc.toSignedString(rollData.dmg.total));
|
||||
this.html.find("label.dmg-arme-actor").text(rollData.dmg.isEmpoignade ? EMPOIGNADE : Misc.toSignedString(rollData.dmg.total));
|
||||
this.html.find("label.arme-mortalite").text(rollData.dmg.mortalite);
|
||||
this.html.find("div.placeholder-ajustements").empty().append(adjustements);
|
||||
this.html.find("div.placeholder-resolution").empty().append(resolutionTable)
|
||||
|
||||
@@ -5,13 +5,13 @@ import { RdDCombat } from "../rdd-combat.js"
|
||||
import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs"
|
||||
import { RdDResolutionTable } from "../rdd-resolution-table.js"
|
||||
import { RDD_CONFIG, renderTemplate } from "../constants.js"
|
||||
import { EMPOIGNADE } from "../item/arme.js"
|
||||
import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js"
|
||||
import { RollTypeCuisine } from "./roll-type-cuisine.mjs"
|
||||
import { RollTypeMeditation } from "./roll-type-meditation.mjs"
|
||||
import { PART_DEFENSE } from "./roll-part-defense.mjs"
|
||||
import { PART_ATTAQUE } from "./roll-part-attaque.mjs"
|
||||
import { RdDRollTables } from "../rdd-rolltables.js"
|
||||
import { RdDEmpoignade } from "../rdd-empoignade.js"
|
||||
|
||||
export default class ChatRollResult {
|
||||
static init() {
|
||||
@@ -67,7 +67,7 @@ export default class ChatRollResult {
|
||||
isShowEncaissement(roll) {
|
||||
switch (roll.type.current) {
|
||||
case ROLL_TYPE_DEFENSE:
|
||||
return roll.rolled.isEchec && roll.attackerRoll?.dmg.mortalite != EMPOIGNADE
|
||||
return roll.rolled.isEchec
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -132,6 +132,7 @@ export default class ChatRollResult {
|
||||
async chatListeners(html) {
|
||||
$(html).on("click", '.appel-chance', event => this.onClickAppelChance(event))
|
||||
$(html).on("click", '.appel-destinee', event => this.onClickAppelDestinee(event))
|
||||
$(html).on("click", '.button-defense', event => this.onClickDefense(event))
|
||||
$(html).on("click", '.encaissement', event => this.onClickEncaissement(event))
|
||||
$(html).on("click", '.resister-recul', event => this.onClickRecul(event))
|
||||
$(html).on("click", '.choix-particuliere', event => this.onClickChoixParticuliere(event))
|
||||
@@ -219,18 +220,41 @@ export default class ChatRollResult {
|
||||
})
|
||||
}
|
||||
|
||||
async onClickEncaissement(event) {
|
||||
async onClickDefense(event) {
|
||||
const chatMessage = ChatUtility.getChatMessage(event)
|
||||
const savedRoll = this.loadChatMessageRoll(chatMessage)
|
||||
const attackerRoll = savedRoll.attackerRoll
|
||||
this.getCombat(attackerRoll)?.defenseV2(attackerRoll,
|
||||
[roll => { ChatUtility.removeChatMessageId(chatMessage.id) }]
|
||||
)
|
||||
}
|
||||
|
||||
async onClickEncaissement(event) {
|
||||
const chatMessage = ChatUtility.getChatMessage(event)
|
||||
const isMessageDemande = ChatUtility.getMessageData(chatMessage, 'demande-defense')
|
||||
const savedRoll = this.loadChatMessageRoll(chatMessage)
|
||||
const attaque = savedRoll.attackerRoll
|
||||
const defender = game.actors.get(savedRoll.ids.actorId)
|
||||
const attacker = game.actors.get(savedRoll.ids.opponentId)
|
||||
const defenderToken = savedRoll.ids.actorTokenId ? canvas.tokens.get(savedRoll.ids.actorTokenId) : undefined
|
||||
const attackerToken = savedRoll.ids.opponentTokenId ? canvas.tokens.get(savedRoll.ids.opponentTokenId) : undefined
|
||||
await defender?.encaisserDommages(attaque.dmg, attacker, undefined, attackerToken, defenderToken)
|
||||
|
||||
savedRoll.done.encaissement = true
|
||||
await this.updateChatMessage(chatMessage, savedRoll)
|
||||
switch (attaque.dmg.mortalite) {
|
||||
case RDD_CONFIG.encaissement.empoignade:
|
||||
savedRoll.done = savedRoll.done ?? {}
|
||||
savedRoll.done.empoignade = await RdDEmpoignade.ajustementEmpoignade(attackerToken.actor, defenderToken.actor)
|
||||
break
|
||||
case RDD_CONFIG.encaissement.entiteincarnee:
|
||||
case RDD_CONFIG.encaissement.nonmortel:
|
||||
case RDD_CONFIG.encaissement.mortel:
|
||||
const defender = defenderToken?.actor ?? game.actors.get(savedRoll.ids.actorId)
|
||||
const attacker = attackerToken?.actor ?? game.actors.get(savedRoll.ids.opponentId)
|
||||
await defender?.encaisserDommages(attaque.dmg, attacker, undefined, attackerToken, defenderToken)
|
||||
break
|
||||
}
|
||||
if (isMessageDemande) {
|
||||
ChatUtility.removeChatMessageId(chatMessage.id)
|
||||
} else {
|
||||
savedRoll.done.encaissement = true
|
||||
await this.updateChatMessage(chatMessage, savedRoll)
|
||||
}
|
||||
}
|
||||
|
||||
async onClickRecul(event) {
|
||||
|
||||
@@ -54,13 +54,27 @@ export class RollBasicParts {
|
||||
}
|
||||
}
|
||||
|
||||
static prepareDefense(attackerRoll) {
|
||||
if (!attackerRoll.passeArme) {
|
||||
attackerRoll.passeArme = foundry.utils.randomID(16);
|
||||
}
|
||||
return {
|
||||
ids: RollBasicParts.reverseIds(attackerRoll),
|
||||
active: attackerRoll.opponent,
|
||||
opponent: attackerRoll.active,
|
||||
attackerRoll: attackerRoll,
|
||||
passeArme: attackerRoll.passeArme,
|
||||
show: { encaissement: true }
|
||||
}
|
||||
}
|
||||
|
||||
static reverseIds(rollData) {
|
||||
return {
|
||||
sceneId: rollData.ids.sceneId,
|
||||
actorId: rollData.ids.opponentId,
|
||||
actorTokenId: rollData.ids.opponentTokenId,
|
||||
opponentId: rollData.ids.actorId,
|
||||
opponentTokenId: rollData.actorTokenId
|
||||
opponentTokenId: rollData.ids.actorTokenId
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ export class RollDialogAdapter {
|
||||
|
||||
const attaque = rollData.current.attaque;
|
||||
const choix = []
|
||||
const isEmpoignade = attaque.dmg.mortalite == 'empoignade';
|
||||
const isEmpoignade = attaque.dmg.isEmpoignade
|
||||
const isCharge = attaque.tactique == 'charge'
|
||||
/* TODO: cas de créatures faisant des lancers, Glou, Glipzouk */
|
||||
const isMeleeDiffNegative = (attaque.comp.type == ITEM_TYPES.competencecreature || rollData.current.carac.key == CARACS.MELEE)
|
||||
|
||||
@@ -44,6 +44,8 @@ import { RollTypeCuisine } from "./roll-type-cuisine.mjs";
|
||||
import { RollPartCuisine } from "./roll-part-cuisine.mjs";
|
||||
import { OptionsAvancees, ROLL_DIALOG_V2_TEST } from "../settings/options-avancees.js";
|
||||
import { ActorImpacts } from "../technical/actor-impacts.mjs";
|
||||
import { RollPartEmpoignade } from "./roll-part-empoignade.mjs";
|
||||
import { RollPartEmpoignadeTaille } from "./roll-part-empoignade-taille.mjs";
|
||||
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api
|
||||
@@ -85,6 +87,8 @@ const ROLL_PARTS = [
|
||||
new RollPartConditions(),
|
||||
new RollPartEthylisme(),
|
||||
new RollPartMalusArmure(),
|
||||
new RollPartEmpoignadeTaille(),
|
||||
new RollPartEmpoignade(),
|
||||
new RollPartEncTotal(),
|
||||
new RollPartSurEnc(),
|
||||
new RollPartAppelMoral(),
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { RDD_CONFIG } from "../constants.js"
|
||||
import { ATTAQUE_TYPE_MELEE } from "../item/arme.js"
|
||||
import { RdDBonus } from "../rdd-bonus.js"
|
||||
import { DIFF, ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs"
|
||||
import { CARACS } from "../rdd-carac.js"
|
||||
import { RdDEmpoignade } from "../rdd-empoignade.js"
|
||||
import { DIFF, ROLL_TYPE_ATTAQUE, ROLL_TYPE_COMP } from "./roll-constants.mjs"
|
||||
import RollDialog from "./roll-dialog.mjs"
|
||||
import { PART_CARAC } from "./roll-part-carac.mjs"
|
||||
import { PART_COMP } from "./roll-part-comp.mjs"
|
||||
import { PART_DIFF } from "./roll-part-diff.mjs"
|
||||
@@ -12,6 +16,10 @@ export const PART_ATTAQUE = 'attaque'
|
||||
|
||||
const TACTIQUES = RdDBonus.tactiques.filter(it => it.isTactique)
|
||||
|
||||
const FILTER_ATTAQUE_EMPOIGNADE = attaque => attaque.arme.isEmpoignade()
|
||||
const FILTER_ATTAQUE_NON_EMPOIGNADE = attaque => !attaque.arme.isEmpoignade()
|
||||
const FILTER_ATTAQUE_EMPOIGNE = attaque => attaque.arme.isUtilisableEmpoigne() && ATTAQUE_TYPE_MELEE.includes(attaque.main)
|
||||
|
||||
export class RollPartAttaque extends RollPartSelect {
|
||||
|
||||
get code() { return PART_ATTAQUE }
|
||||
@@ -22,7 +30,8 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
loadRefs(rollData) {
|
||||
const refs = this.getRefs(rollData)
|
||||
const attaques = rollData.active.actor.listAttaques()
|
||||
refs.attaques = attaques.map(it => RollPartAttaque.$extractAttaque(it, rollData.active.actor))
|
||||
refs.all = attaques.map(it => RollPartAttaque.$extractAttaque(it, rollData.active.actor))
|
||||
this.filterAttaquesEmpoignade(rollData)
|
||||
refs.tactiques = TACTIQUES
|
||||
if (refs.attaques.length > 0) {
|
||||
const attaque = this.findAttaque(refs.attaques, this.getSaved(rollData))
|
||||
@@ -30,6 +39,10 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
}
|
||||
}
|
||||
|
||||
isAttaqueEmpoignade(it) {
|
||||
return it.arme.isEmpoignade()
|
||||
}
|
||||
|
||||
store(rollData, targetData) {
|
||||
super.store(rollData, targetData)
|
||||
this.getSaved(targetData).dmg = this.getCurrent(rollData).dmg
|
||||
@@ -59,10 +72,23 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
}
|
||||
|
||||
prepareContext(rollData) {
|
||||
this.filterAttaquesEmpoignade(rollData)
|
||||
const current = this.getCurrent(rollData)
|
||||
current.dmg = RdDBonus.dmgRollV2(rollData, current)
|
||||
}
|
||||
|
||||
filterAttaquesEmpoignade(rollData) {
|
||||
const refs = this.getRefs(rollData)
|
||||
const isEmpoignade = RdDEmpoignade.isCombatantEmpoignade(rollData.ids.actorId, rollData.ids.actorTokenId)
|
||||
refs.isEmpoignadeEnCours = RdDEmpoignade.isEmpoignadeEnCours(rollData.active.actor)
|
||||
const filterAttaques = isEmpoignade ?
|
||||
FILTER_ATTAQUE_EMPOIGNADE
|
||||
: refs.isEmpoignadeEnCours
|
||||
? FILTER_ATTAQUE_EMPOIGNE
|
||||
: FILTER_ATTAQUE_NON_EMPOIGNADE
|
||||
refs.attaques = refs.all.filter(filterAttaques)
|
||||
}
|
||||
|
||||
getAjustements(rollData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
const tactique = current.tactique ? [{ label: current.tactique.label, value: current.tactique.attaque }] : []
|
||||
@@ -79,6 +105,7 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
const selectAttaque = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-attaque"]`)
|
||||
const selectTactique = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-tactique"]`)
|
||||
const checkMortalite = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="check-mortalite"]`)
|
||||
const utiliserDagueEmpoignade = rollDialog.element.querySelector(`roll-section[name="${this.code}"] a.utiliser-dague-empoignade`)
|
||||
const current = this.getCurrent(rollDialog.rollData)
|
||||
|
||||
selectAttaque.addEventListener("change", e => {
|
||||
@@ -99,6 +126,23 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
current.dmg.mortalite = (e.currentTarget.checked ? RDD_CONFIG.encaissement.mortel : RDD_CONFIG.encaissement.nonmortel)
|
||||
rollDialog.render()
|
||||
})
|
||||
utiliserDagueEmpoignade?.addEventListener("click", e => {
|
||||
e.preventDefault()
|
||||
const rollData = rollDialog.rollData
|
||||
this.utiliserDagueEmpoignade(rollData)
|
||||
})
|
||||
}
|
||||
|
||||
utiliserDagueEmpoignade(rollData) {
|
||||
RollDialog.create({
|
||||
ids: { actorId: rollData.ids.actorId, actorTokenId: rollData.ids.actorTokenId },
|
||||
type: { allowed: [ROLL_TYPE_COMP], current: ROLL_TYPE_COMP },
|
||||
selected: {
|
||||
carac: { key: CARACS.DEXTERITE, forced: true },
|
||||
comp: { key: 'Dague', forced: true },
|
||||
diff: { type: DIFF.IMPOSEE, value: -4 }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
impactOtherPart(part, rollData) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Grammar } from "../grammar.js"
|
||||
import { RollPartSelect } from "./roll-part-select.mjs"
|
||||
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
|
||||
|
||||
@@ -12,8 +13,14 @@ export class RollPartCarac extends RollPartSelect {
|
||||
|
||||
loadRefs(rollData) {
|
||||
const refs = this.getRefs(rollData)
|
||||
const selected = this.getSelected(rollData)
|
||||
const actor = rollData.active.actor
|
||||
refs.all = [...this.$getActorCaracs(actor), ...this.$getCaracCompetenceCreature(actor)]
|
||||
.filter(c => !selected.forced ||
|
||||
(selected.key ?
|
||||
Grammar.includesLowerCaseNoAccent(c.label, selected.key)
|
||||
: c.key == '')
|
||||
)
|
||||
refs.caracs = refs.all
|
||||
this.$selectCarac(rollData)
|
||||
}
|
||||
|
||||
@@ -18,12 +18,16 @@ export class RollPartComp extends RollPartSelect {
|
||||
loadRefs(rollData) {
|
||||
const refs = this.getRefs(rollData)
|
||||
const selected = this.getSelected(rollData)
|
||||
refs.all = this.$getActorComps(rollData)
|
||||
.filter(comp => !selected.forced ||
|
||||
(selected.key ?
|
||||
Grammar.includesLowerCaseNoAccent(comp.name, selected.key)
|
||||
: comp.key == '')
|
||||
)
|
||||
const all = this.$getActorComps(rollData)
|
||||
if (selected.forced) {
|
||||
refs.all = all.filter(comp => Grammar.equalsInsensitive(comp.label, selected.key))
|
||||
if (refs.all.length == 0) {
|
||||
refs.all = all.filter(comp => Grammar.includesLowerCaseNoAccent(comp.label, selected.key))
|
||||
}
|
||||
}
|
||||
else {
|
||||
refs.all = all
|
||||
}
|
||||
refs.comps = refs.all
|
||||
this.$selectComp(rollData)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ITEM_TYPES } from "../constants.js"
|
||||
import { ITEM_TYPES, RDD_CONFIG } from "../constants.js"
|
||||
import { ATTAQUE_TYPE, RdDItemArme } from "../item/arme.js"
|
||||
import { CARACS } from "../rdd-carac.js"
|
||||
import { DIFF, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs"
|
||||
@@ -15,6 +15,8 @@ export class RollPartDefense extends RollPartSelect {
|
||||
|
||||
get code() { return PART_DEFENSE }
|
||||
get section() { return ROLLDIALOG_SECTION.CHOIX }
|
||||
|
||||
isValid(rollData) { return rollData.attackerRoll != undefined }
|
||||
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_DEFENSE) }
|
||||
|
||||
static getDiffAttaque(attackerRoll) {
|
||||
@@ -27,13 +29,22 @@ export class RollPartDefense extends RollPartSelect {
|
||||
const attackerRoll = rollData.attackerRoll
|
||||
const defenseur = rollData.active.actor
|
||||
refs.isDistance = [ATTAQUE_TYPE.TIR, ATTAQUE_TYPE.LANCER].find(it => it == attackerRoll?.main)
|
||||
const esquives = refs.isDistance == ATTAQUE_TYPE.TIR ? [] : defenseur.getCompetencesEsquive()
|
||||
.map(it => RollPartDefense.$extractEsquive(it, defenseur))
|
||||
const isEmpoignade = attackerRoll.dmg.isEmpoignade
|
||||
const isEmpoignadeEnCours = isEmpoignade && defenseur.itemTypes[ITEM_TYPES.empoignade].find(it =>
|
||||
[it.system.empoigneurid, it.system.empoigneid].includes(rollData.ids.opponentId) &&
|
||||
it.system.pointsemp != 0)
|
||||
|
||||
const parades = defenseur.items.filter(it => it.isParade() && (!refs.isDistance || it.isBouclier()))
|
||||
.map(it => RollPartDefense.$extractParade(it, attackerRoll?.arme, defenseur))
|
||||
const esquives = (refs.isDistance == ATTAQUE_TYPE.TIR || isEmpoignadeEnCours)
|
||||
? []
|
||||
: defenseur.getCompetencesEsquive()
|
||||
const parades = isEmpoignade
|
||||
? [RdDItemArme.empoignade(defenseur)]
|
||||
: defenseur.items.filter(it => it.isParade() && (!refs.isDistance || it.isBouclier()))
|
||||
|
||||
refs.defenses = [...esquives, ...parades].filter(it => it != undefined)
|
||||
refs.defenses = [
|
||||
...esquives.map(it => RollPartDefense.$extractEsquive(it, defenseur)),
|
||||
...parades.map(it => RollPartDefense.$extractParade(it, attackerRoll?.arme, defenseur))
|
||||
]
|
||||
this.$selectDefense(rollData)
|
||||
}
|
||||
|
||||
|
||||
40
module/roll/roll-part-empoignade-taille.mjs
Normal file
40
module/roll/roll-part-empoignade-taille.mjs
Normal file
@@ -0,0 +1,40 @@
|
||||
import { RDD_CONFIG } from "../constants.js"
|
||||
import { ATTAQUE_TYPE_MELEE } from "../item/arme.js"
|
||||
import { RdDEmpoignade } from "../rdd-empoignade.js"
|
||||
import { COMBAT_ROLL_TYPES } from "./roll-constants.mjs"
|
||||
import { PART_ATTAQUE } from "./roll-part-attaque.mjs"
|
||||
import { RollPartCheckbox } from "./roll-part-checkbox.mjs"
|
||||
|
||||
const EMPOIGNADE_TAILLE = "empoignade-taille"
|
||||
|
||||
export class RollPartEmpoignadeTaille extends RollPartCheckbox {
|
||||
|
||||
get code() { return EMPOIGNADE_TAILLE }
|
||||
|
||||
isValid(rollData) {
|
||||
return RdDEmpoignade.isCombatantEmpoignade(rollData.ids.actorId, rollData.ids.actorTokenId)
|
||||
}
|
||||
|
||||
visible(rollData) {
|
||||
return COMBAT_ROLL_TYPES.includes(rollData.type.current) &&
|
||||
RdDEmpoignade.isEmpoignadeEnCours(rollData.active.actor) &&
|
||||
this.getTailleDiff(rollData) != 0
|
||||
}
|
||||
|
||||
getTailleDiff(rollData) {
|
||||
const taille = rollData.active.actor.getTaille()
|
||||
const tailleOpponent = rollData.opponent.actor.getTaille()
|
||||
const diff = taille - tailleOpponent
|
||||
const diffTailleAbs = Math.max(0, Math.abs(diff) - 1)
|
||||
const signDiff = Math.sign(diff)
|
||||
return signDiff * diffTailleAbs
|
||||
}
|
||||
|
||||
getCheckboxIcon(rollData) { return `<img src="${RDD_CONFIG.icons.empoignade}">` }
|
||||
getCheckboxLabel(rollData) {
|
||||
return `Taille ${rollData.active.actor.getTaille()} vs ${rollData.opponent.actor.getTaille()} `
|
||||
}
|
||||
getCheckboxValue(rollData) {
|
||||
return this.getTailleDiff(rollData)
|
||||
}
|
||||
}
|
||||
30
module/roll/roll-part-empoignade.mjs
Normal file
30
module/roll/roll-part-empoignade.mjs
Normal file
@@ -0,0 +1,30 @@
|
||||
import { RDD_CONFIG } from "../constants.js"
|
||||
import { ATTAQUE_TYPE_MELEE } from "../item/arme.js"
|
||||
import { RdDEmpoignade } from "../rdd-empoignade.js"
|
||||
import { ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs"
|
||||
import { PART_ATTAQUE } from "./roll-part-attaque.mjs"
|
||||
import { RollPartCheckbox } from "./roll-part-checkbox.mjs"
|
||||
|
||||
const EMPOIGNADE = "empoignade"
|
||||
|
||||
export class RollPartEmpoignade extends RollPartCheckbox {
|
||||
|
||||
get code() { return EMPOIGNADE }
|
||||
|
||||
isValid(rollData) {
|
||||
return RdDEmpoignade.isCombatantEmpoignade(rollData.ids.opponentId, rollData.ids.opponentTokenId) &&
|
||||
!RdDEmpoignade.isCombatantEmpoignade(rollData.ids.actorId, rollData.ids.actorTokenId)
|
||||
}
|
||||
|
||||
visible(rollData) {
|
||||
return rollData.type.current == ROLL_TYPE_ATTAQUE &&
|
||||
ATTAQUE_TYPE_MELEE.includes(rollData.current[PART_ATTAQUE].main) &&
|
||||
RdDEmpoignade.isCombatantEmpoignade(rollData.ids.opponentId, rollData.ids.opponentTokenId) &&
|
||||
!RdDEmpoignade.isCombatantEmpoignade(rollData.ids.actorId, rollData.ids.actorTokenId) &&
|
||||
!RdDEmpoignade.isEmpoignadeEnCours(rollData.active.actor)
|
||||
}
|
||||
|
||||
getCheckboxIcon(rollData) { return `<img src="${RDD_CONFIG.icons.empoignade}">` }
|
||||
getCheckboxLabel(rollData) { return "vs. empoigneur" }
|
||||
getCheckboxValue(rollData) { return 4 }
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { RDD_CONFIG } from "../constants.js"
|
||||
import { RdDItemCompetence } from "../item-competence.js"
|
||||
import { RdDCarac } from "../rdd-carac.js"
|
||||
import { RollPartCheckbox } from "./roll-part-checkbox.mjs"
|
||||
@@ -25,7 +26,7 @@ export class RollPartEncTotal extends RollPartCheckbox {
|
||||
})
|
||||
}
|
||||
|
||||
getCheckboxIcon(rollData) { return '<i class="fa-solid fa-weight-hanging"></i>' }
|
||||
getCheckboxIcon(rollData) { return `<img src="${RDD_CONFIG.icons.surenc}">` }
|
||||
getCheckboxLabel(rollData) { return "Enc. total" }
|
||||
getCheckboxValue(rollData) { return - rollData.active.actor.getEncTotal() }
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ export class RollPartMeditation extends RollPartSelect {
|
||||
|
||||
getAjustements(rollData) {
|
||||
const malus = this.getMalusEchecs(rollData)
|
||||
const malusEchecs = malusEchecs == 0 ? [] : [{ label: "Méditation", value: malus }]
|
||||
const malusEchecs = malus == 0 ? [] : [{ label: "Méditation", value: malus }]
|
||||
const malusConditions = { label: "Conditions", value: this.getMalusConditions(rollData) }
|
||||
return [malusConditions, ...malusEchecs]
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { RDD_CONFIG } from "../constants.js"
|
||||
import { RdDCarac } from "../rdd-carac.js"
|
||||
import { RollPartCheckbox } from "./roll-part-checkbox.mjs"
|
||||
|
||||
@@ -10,7 +11,7 @@ export class RollPartSurEnc extends RollPartCheckbox {
|
||||
visible(rollData) {
|
||||
return RdDCarac.isActionPhysique(rollData.current.carac.key) && rollData.active.actor.isSurenc()
|
||||
}
|
||||
getCheckboxIcon(rollData) { return '<i class="fa-solid fa-weight-hanging"></i>' }
|
||||
getCheckboxIcon(rollData) { return `<img src="${RDD_CONFIG.icons.surenc}">` }
|
||||
getCheckboxLabel(rollData) { return "Sur-enc." }
|
||||
getCheckboxValue(rollData) { return rollData.active.actor.computeMalusSurEncombrement() }
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ export class RollType {
|
||||
}
|
||||
|
||||
setDiffType(rollData, type) {
|
||||
type = rollData.selected[PART_DIFF].type ?? type
|
||||
rollData.current[PART_DIFF].type = type
|
||||
this.setRollDataType(rollData)
|
||||
}
|
||||
|
||||
@@ -14,16 +14,17 @@ export const STATUSES = {
|
||||
StatusBleeding: 'bleeding',
|
||||
StatusDead: 'dead',
|
||||
StatusDemiReve: 'demi-reve',
|
||||
StatusSurEnc: 'sur-encombrement',
|
||||
StatusForceWeak: 'force insuffisante',
|
||||
}
|
||||
|
||||
export const forceWeakStatusEffect = { rdd: true, id: STATUSES.StatusForceWeak, name: 'EFFECT.StatusForceWeak', img: RDD_CONFIG.icons.forceWeak };
|
||||
export const demiReveStatusEffect = {
|
||||
rdd: true, id: STATUSES.StatusDemiReve, name: 'EFFECT.StatusDemiReve', img: RDD_CONFIG.icons.demiReve
|
||||
};
|
||||
export const surEncEffect = { rdd: true, id: STATUSES.StatusSurEnc, name: 'EFFECT.StatusSurEnc', img: RDD_CONFIG.icons.surenc };
|
||||
export const demiReveStatusEffect = { rdd: true, id: STATUSES.StatusDemiReve, name: 'EFFECT.StatusDemiReve', img: RDD_CONFIG.icons.demiReve };
|
||||
|
||||
const rddStatusEffects = [
|
||||
{ rdd: true, id: STATUSES.StatusGrappling, tint: '#33cc33', name: 'EFFECT.StatusGrappling', img: RDD_CONFIG.icons.empoignade },
|
||||
{ rdd: true, id: STATUSES.StatusGrappled, tint: '#ff9900', name: 'EFFECT.StatusGrappled', img: RDD_CONFIG.icons.empoignade },
|
||||
{ rdd: true, id: STATUSES.StatusGrappling, name: 'EFFECT.StatusGrappling', img: RDD_CONFIG.icons.empoignade },
|
||||
{ rdd: true, id: STATUSES.StatusGrappled, tint: '#d5633d', name: 'EFFECT.StatusGrappled', img: RDD_CONFIG.icons.empoignade },
|
||||
|
||||
{ rdd: true, id: STATUSES.StatusRestrained, name: 'EFFECT.StatusRestrained', img: 'icons/svg/net.svg' },
|
||||
{ rdd: true, id: STATUSES.StatusStunned, name: 'EFFECT.StatusStunned', img: 'icons/svg/stoned.svg', "duration.rounds": 1 },
|
||||
@@ -36,7 +37,8 @@ const rddStatusEffects = [
|
||||
{ rdd: true, id: STATUSES.StatusBleeding, name: 'EFFECT.StatusBleeding', img: 'icons/svg/blood.svg' },
|
||||
{ rdd: true, id: STATUSES.StatusDead, name: 'EFFECT.StatusDead', img: 'icons/svg/skull.svg' },
|
||||
demiReveStatusEffect,
|
||||
forceWeakStatusEffect
|
||||
forceWeakStatusEffect,
|
||||
surEncEffect,
|
||||
];
|
||||
|
||||
const statusDemiSurprise = new Set([STATUSES.StatusStunned, STATUSES.StatusProne, STATUSES.StatusRestrained, STATUSES.StatusForceWeak])
|
||||
@@ -45,8 +47,9 @@ const statusSurpriseTotale = new Set([STATUSES.StatusUnconscious, STATUSES.Statu
|
||||
export class StatusEffects extends FormApplication {
|
||||
|
||||
static onReady() {
|
||||
const rddEffectIds = rddStatusEffects.map(it => it.id);
|
||||
const rddEffectIds = rddStatusEffects.map(it => it.id)
|
||||
rddStatusEffects.forEach(it => {
|
||||
it.name = game.i18n.localize(it.name)
|
||||
it.statuses = new Set([it.id])
|
||||
})
|
||||
const defaultStatusEffectIds = CONFIG.statusEffects.map(it => it.id);
|
||||
@@ -135,7 +138,7 @@ export class StatusEffects extends FormApplication {
|
||||
}
|
||||
|
||||
static prepareActiveEffect(effectId) {
|
||||
let status = rddStatusEffects.find(it => it.id == effectId)
|
||||
let status = rddStatusEffects.find(it => it.statuses? it.statuses.has(effectId) : it.id == effectId)
|
||||
if (status) {
|
||||
status = foundry.utils.duplicate(status)
|
||||
status.statuses = new Set([effectId])
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"dependencies": {
|
||||
"gulp": "^5.0.0",
|
||||
"gulp-less": "^5.0.0",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"rollup-plugin-visualizer": "^5.12.0"
|
||||
},
|
||||
"repository": {
|
||||
|
||||
21
pdf-lib-LICENSE.md
Normal file
21
pdf-lib-LICENSE.md
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Andrew Dillon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -4,7 +4,7 @@
|
||||
<li class="caracteristique flexrow list-item {{#if carac.isLevelUp}}xp-level-up{{/if}}" data-attribute="{{key}}">
|
||||
{{#if (eq key 'taille')}}
|
||||
<span class="carac-label" name="system.carac.{{key}}.label">{{carac.label}}</span>
|
||||
<input class="carac-value" type="number" name="system.carac.{{key}}.value" value="{{carac.value}}" data-dtype="number" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
|
||||
<input class="carac-value" type="number" name="carac.{{key}}" value="{{carac.value}}" data-dtype="number" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
|
||||
<label class="carac-xp"/>
|
||||
{{else}}
|
||||
{{#if (actor-default @root.type 'carac' key 'derivee')}}
|
||||
@@ -23,7 +23,7 @@
|
||||
{{else}}
|
||||
<span class="carac-label" name="system.carac.{{key}}.label"><a class="roll-carac" data-carac-name={{key}}>{{carac.label}}</a></span>
|
||||
{{/if}}
|
||||
<input class="carac-value" type="number" name="system.carac.{{key}}.value" value="{{carac.value}}" data-dtype="number" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
|
||||
<input class="carac-value" type="number" name="carac.{{key}}" value="{{carac.value}}" data-dtype="number" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
|
||||
<span class="carac-xp">
|
||||
<input class="carac-xp" type="number" name="system.carac.{{key}}.xp" value="{{carac.xp}}" data-dtype="number"
|
||||
data-tooltip="Vous devez acquérir {{carac.xpNext}} points d'Experience pour augmenter votre {{carac.label}}"
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
</div>
|
||||
<hr>
|
||||
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire.hbs"}}
|
||||
{{log @root.options}}
|
||||
{{#unless system.illimite}}
|
||||
{{#if @root.options.isObserver}}
|
||||
<hr>
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
{{log this}}
|
||||
<div class="roll-chat" data-passearme="{{passeArme}}">
|
||||
<div class="chat-img">
|
||||
<img src="{{opponent.img}}" data-tooltip="{{opponent.name}}" />
|
||||
<img src="{{active.img}}" data-tooltip="{{active.name}}" />
|
||||
</div>
|
||||
|
||||
<div class="chat-header">
|
||||
<h4>Défense de {{opponent.name}}</h4>
|
||||
<h4>Défense de {{active.name}}</h4>
|
||||
</div>
|
||||
|
||||
<div class="chat-resume">
|
||||
{{#if (eq opponent.surprise.key 'totale')}}
|
||||
<span><strong>{{opponent.name}}</strong> est totalement surpris</span>
|
||||
{{#if (eq active.surprise.key 'totale')}}
|
||||
<span><strong>{{active.name}}</strong> est totalement surpris</span>
|
||||
{{else}}
|
||||
<span><strong>{{opponent.name}}</strong> doit se défendre
|
||||
{{~#if (eq opponent.surprise.key 'demi')}} avec une significative {{/if}} d'une attaque
|
||||
{{~#if particuliere}} <strong>particulière en
|
||||
{{~#if (eq particuliere 'finesse')}} finesse
|
||||
<span><strong>{{active.name}}</strong> doit se défendre
|
||||
{{~#if (eq active.surprise.key 'demi')}} avec une significative {{/if}} d'une attaque
|
||||
{{~#if attackerRoll.particuliere}} <strong>particulière en
|
||||
{{~#if (eq attackerRoll.particuliere 'finesse')}} finesse
|
||||
{{else if (eq particuliere 'force')}} force
|
||||
{{else if (eq particuliere 'rapidite')}} rapidité
|
||||
{{/if~}}</strong>
|
||||
{{/if}} de {{active.name}} ({{current.attaque.label}}):
|
||||
{{/if}} de {{opponent.name}} ({{attackerRoll.current.attaque.label}}):
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
@@ -28,30 +27,23 @@
|
||||
</div>
|
||||
|
||||
<div class="chat-actions">
|
||||
{{#unless (eq opponent.surprise.key 'totale')}}
|
||||
{{#unless (eq active.surprise.key 'totale')}}
|
||||
<a class='chat-card-button button-defense'
|
||||
data-attackerId='{{ids.actorId}}'
|
||||
data-attackerTokenId='{{ids.actorTokenId}}'
|
||||
data-defenderTokenId='{{ids.opponentTokenId}}'
|
||||
data-attackerId='{{ids.opponentId}}'
|
||||
data-attackerTokenId='{{ids.opponentTokenId}}'
|
||||
data-defenderId='{{ids.actorId}}'
|
||||
data-defenderTokenId='{{ids.actorTokenId}}'
|
||||
>
|
||||
<img src="systems/foundryvtt-reve-de-dragon/assets/actions/defense.svg"/>
|
||||
Se défendre
|
||||
{{#if (or (eq attaqueCategorie 'tir') (eq attaqueCategorie 'lancer'))}}
|
||||
{{#if (or (eq attackerRoll.attaqueCategorie 'tir') (eq attackerRoll.attaqueCategorie 'lancer'))}}
|
||||
(difficulté à déterminer)
|
||||
{{else}}
|
||||
à {{current.diff.value}}
|
||||
à {{attackerRoll.current.diff.value}}
|
||||
{{/if}}
|
||||
</a>
|
||||
{{/unless}}
|
||||
{{#unless (eq dmg.mortalite 'empoignade')}}
|
||||
<a class='chat-card-button encaissement'
|
||||
data-tooltip="Encaisser à {{plusMoins dmg.total}} {{#if (eq dmg.mortalite 'non-mortel')~}}(non-mortel){{/if}}"
|
||||
>
|
||||
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/encaisser.svg"/>
|
||||
Encaisser à {{plusMoins dmg.total}}
|
||||
{{#if (eq dmg.mortalite 'non-mortel')~}}(non-mortel){{/if}}
|
||||
</a>
|
||||
{{/unless}}
|
||||
{{> 'partial-encaissement'}}
|
||||
</div>
|
||||
|
||||
<div class="chat-buttons">
|
||||
|
||||
@@ -1,15 +1,29 @@
|
||||
{{log 'partial-encaissement' this}}
|
||||
{{#if show.encaissement}}
|
||||
{{#if done.encaissement}}
|
||||
<span class='chat-card-info'>
|
||||
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/encaisser.svg"/>
|
||||
{{active.name}} a encaissé
|
||||
</span>
|
||||
<span class='chat-card-info'>
|
||||
{{#if (eq attackerRoll.dmg.mortalite 'empoignade')}}
|
||||
<img src="systems/foundryvtt-reve-de-dragon/assets/actions/empoignade.svg"/>
|
||||
{{opponent.name}} a {{done.empoignade.system.pointsemp}} point d'empoignade contre {{active.name}}.
|
||||
{{#if (gt done.empoignade.system.pointsemp 2)}} Si {{active.name}} ne se libère pas, il sera immobilisé à la fin du round{{/if}}
|
||||
{{else}}
|
||||
<img src="systems/foundryvtt-reve-de-dragon/assets/actions/encaisser.svg"/>
|
||||
{{active.name}} a encaissé
|
||||
{{/if}}
|
||||
</span>
|
||||
{{else}}
|
||||
<a class='chat-card-button encaissement'
|
||||
data-tooltip="Encaisser à {{plusMoins attackerRoll.dmg.total}} {{#if (eq attackerRoll.dmg.mortalite 'non-mortel')~}}(non-mortel){{/if}}"
|
||||
>
|
||||
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/encaisser.svg"/> Encaisser à {{plusMoins attackerRoll.dmg.total}}
|
||||
{{#if (eq attackerRoll.dmg.mortalite 'non-mortel')~}}(non-mortel){{/if}}
|
||||
</a>
|
||||
{{#if (eq attackerRoll.dmg.mortalite 'empoignade')}}
|
||||
<a class='chat-card-button encaissement' data-tooltip="Marquer un point d'empoignade">
|
||||
<img src="systems/foundryvtt-reve-de-dragon/assets/actions/empoignade.svg"/>
|
||||
Marquer un point d'empoignade
|
||||
</a>
|
||||
{{else}}
|
||||
<a class='chat-card-button encaissement'
|
||||
data-tooltip="Encaisser à {{plusMoins attackerRoll.dmg.total}} {{#if (eq attackerRoll.dmg.mortalite 'non-mortel')~}}(non-mortel){{/if}}"
|
||||
>
|
||||
<img src="systems/foundryvtt-reve-de-dragon/assets/actions/encaisser.svg"/> Encaisser à {{plusMoins attackerRoll.dmg.total}}
|
||||
{{#if (eq attackerRoll.dmg.mortalite 'non-mortel')~}}(non-mortel){{/if}}
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
@@ -15,19 +15,32 @@
|
||||
{{selectOptions refs.tactiques selected=current.tactique.key valueAttr="key" labelAttr="label"}}
|
||||
</select>
|
||||
</subline>
|
||||
<subline>
|
||||
{{#if (eq current.arme.system.mortalite 'empoignade')}}
|
||||
Empoignade, pas de dommages directs
|
||||
{{else}}
|
||||
{{#if (and (ne current.arme.system.mortalite 'non-mortel') (eq current.dmg.penetration 0))}}
|
||||
<input name="check-mortalite" type="checkbox" {{#if (eq current.dmg.mortalite 'mortel')}}checked{{/if}} />
|
||||
{{/if}}
|
||||
{{#if (and refs.isEmpoignadeEnCours (eq current.arme.system.competence 'Dague'))}}
|
||||
<subline>
|
||||
<span>
|
||||
Pour pouvoir attaquer avec une dague en cours d'empoignade, il faut réussir:<br>
|
||||
<a class='chat-card-button utiliser-dague-empoignade'>DEXTÉRITÉ / Dague à -4</a>
|
||||
<br>En cas d'échec total, {{rollData.active.name}} sera désarmé.
|
||||
</span>
|
||||
</subline>
|
||||
{{/if}}
|
||||
{{#if (eq current.arme.system.mortalite 'empoignade')}}
|
||||
<subline>
|
||||
Empoignade, pas de dommages directs.<br>
|
||||
Si {{either rollData.opponent.name}} est équipé d'une arme de mêlée, ou attaque
|
||||
à mains nues (pugilat), il bénéficie d'un bonus de +4 à son attaque.
|
||||
</subline>
|
||||
{{else}}
|
||||
<subline>
|
||||
{{#if (and (ne current.arme.system.mortalite 'non-mortel') (eq current.dmg.penetration 0))}}
|
||||
<input name="check-mortalite" type="checkbox" {{#if (eq current.dmg.mortalite 'mortel')}}checked{{/if}} />
|
||||
{{/if}}
|
||||
<label for="check-mortalite">
|
||||
Dommages: {{plusMoins current.dmg.total}} ({{current.dmg.mortalite}})
|
||||
{{~#if current.dmg.penetration}}, pénétration {{current.dmg.penetration}}{{/if}}
|
||||
</label>
|
||||
{{/if}}
|
||||
</subline>
|
||||
</subline>
|
||||
{{/if}}
|
||||
{{#if rollData.active.effets}}
|
||||
<subline>
|
||||
<span class="status-surprise">
|
||||
|
||||
Reference in New Issue
Block a user