Compare commits

...

52 Commits
13.0.28 ... v13

Author SHA1 Message Date
6b0a6a268e Merge pull request '13.0.36 - Les rêveries d'Illisys' (#801) from feature/v13-corrections into v13
Some checks failed
Release Creation / build (release) Failing after 1h28m41s
Reviewed-on: https, #801
2026-04-30 18:25:47 +02:00
c7da930556 Boutons dans les listes d'équipement
Affichage amélioré en évitant les retours à la ligne
Meilleur affichage des -/+
2026-04-30 00:05:31 +02:00
e9e2eba9b5 Support v14: commandes dans chatMessage en html 2026-04-29 22:53:23 +02:00
423dcaf53e Cuisiner depuis l'équipement 2026-04-29 22:53:23 +02:00
a01086ff28 Amélioration champs input
- ajout de min et max quand utile
- ordre et regroupement des attributs:
   - préférence pour name en premier
   - regroupement de class/type/data-dtype
   - regroupement value/min/max
2026-04-29 22:53:22 +02:00
76e651cf19 Corrections mineures 2026-04-28 19:21:00 +02:00
eaee50511a Fix v14: attaque à distance 2026-04-28 19:10:38 +02:00
d1832917bc Message de dommage sur entité
Plutôt que de dire "ne subit aucun dommage", une gravité de blessure
indicative est donnée
2026-04-28 19:09:08 +02:00
277799088f Affichage des jeux 2026-04-28 19:07:24 +02:00
0398fbdbd1 Fix: Pas d'affichage de feuille sur encaissement 2026-04-28 19:07:00 +02:00
4faa9b6b54 Merge pull request 'Quelques corrections mineures' (#800) from feature/v13-corrections into v13
All checks were successful
Release Creation / build (release) Successful in 1m40s
Reviewed-on: https, #800
2026-04-26 22:38:40 +02:00
43a09f3a99 Compatibilité v14 2026-04-26 22:37:49 +02:00
ec8fc795f4 Affichage état & blessures
Les icônes d'effets sont affichées en premier.

Affichage des contusions. Les blessures sont affichées en
dernier, par gravité décroissante
2026-04-26 22:37:49 +02:00
8b46ea3681 Ajout de tokens de créatures 2026-04-26 22:37:49 +02:00
3ce33eeea3 simplification pre-update checkCompetence 2026-04-26 22:37:48 +02:00
5c4292882f Correction des updates multiples
Utilisation d'un render sur timer pour forcer le réaffichage
2026-04-26 22:37:48 +02:00
fb150753e0 Suppression image de fond "players"
Adaptation theme Foundry v13
2026-04-26 22:37:48 +02:00
fa54865369 Amélioration des tirages
- option pour ne pas afficher la table source
- les tirages de rencontres sont entre joueur et MJ
2026-04-26 22:37:48 +02:00
200e35b7b7 Filtrage des actions des items des commerces 2026-04-26 22:37:48 +02:00
76fb385c69 Visibilité des tirages dans le compendium
Les tirages de queues, têtes, ... ne concernent plus tout le monde,
mais le joueur et le MJ
2026-04-26 22:37:48 +02:00
ef30e76449 Fix: recul contre entité de cauchemar 2026-04-26 22:37:47 +02:00
10aba8bd58 Fix: sortie d'objet de conteneur 2026-04-26 22:37:47 +02:00
0aedff9d4b Merge pull request 'v13.0.34 - La saumuche d'Illysis' (#799) from feature/v13-corrections into v13
All checks were successful
Release Creation / build (release) Successful in 2m2s
Reviewed-on: https, #799
2026-04-07 19:23:26 +02:00
6062d0428c Fix: difficulté d'annulation de magie 2026-04-03 22:16:50 +02:00
eebca509bd Fix: affichage appel moral sur sorts 2026-04-03 22:16:50 +02:00
9934fe9191 Le pluriel de jeu est jeux 2026-04-03 22:16:50 +02:00
e6c4f7990a Correction: qualité des improvisations de cuisine 2026-04-03 22:16:50 +02:00
956fecdd82 Demi-rêve masqué, masquer les rencontres
Pour éviter de trahir l'emplacement du demi-rêve...
2026-04-03 22:16:50 +02:00
afcd200913 Merge pull request 'v13.0.33 - L'ébriété d'Illysis' (#798) from feature/v13-corrections into v13
All checks were successful
Release Creation / build (release) Successful in 1m31s
Reviewed-on: https, #798
2026-03-26 23:11:26 +01:00
f3e7cc38a7 Message de Vaisseau 2026-03-24 20:45:54 +01:00
bcc1ec6a37 Pas de perte d'endurance quand éméché 2026-03-24 20:45:54 +01:00
4141eeaa4a Cleanup: gererExperience=>ajoutExperience 2026-03-24 20:45:54 +01:00
d80efba092 Corrections relecture IA 2026-03-24 20:45:54 +01:00
a768419029 Merge pull request '## 13.0.32 - Le surpoids d'Illysis' (#797) from feature/v13-corrections into v13
All checks were successful
Release Creation / build (release) Successful in 2m42s
Reviewed-on: https, #797
2026-03-09 09:47:19 +01:00
dfc73fb96d Fix: affichage blessures et pertes
Les pertes et la récupération sont correctement gérées (en ne
faisant qu'un seul render pour le personnage)
2026-03-07 20:38:28 +01:00
9bb9a3b0eb Icône "sonné" inline dans le tchat 2026-03-07 20:38:28 +01:00
3f014faf02 Pas de perte endurance blessures graves soignées 2026-03-07 20:38:12 +01:00
6f30913a8f Visibilité ajustement conditions 2026-03-07 20:38:11 +01:00
b326484797 Fix: malus encombrement 2026-03-07 20:38:11 +01:00
fd96be439e Merge pull request '13.0.31 - Les choix multiples d'Illysis' (#796) from feature/v13-corrections into v13
All checks were successful
Release Creation / build (release) Successful in 1m57s
Reviewed-on: https, #796
2026-03-04 09:01:53 +01:00
238d99fa9b Fix: dommages armes 1/2 mains à deux mains 2026-03-03 18:14:58 +01:00
490de5882b Fix: valeurs par défaut après la sélection 2026-03-03 17:58:52 +01:00
4fc06a449c Merge pull request '13.0.30 - Le pansement d'Illysis' (#795) from feature/v13-corrections into v13
All checks were successful
Release Creation / build (release) Successful in 1m27s
Reviewed-on: https, #795
2026-02-18 00:43:46 +01:00
929d6af173 Saisie de valeurs négatives 2026-02-17 00:36:08 +01:00
e15ed9d05d Jet de compétence avec défauts
Utilisation de carac par défaut et difficulté par défaut à l'ouverture
de la fenêtre de jet depuis une compétence
2026-02-16 23:58:45 +01:00
3699bc19b8 Fix: soins d'un joueur à l'autre
Les données dans rollData ne pouvaient pas être serialisées
2026-02-06 13:42:27 +01:00
15510b99d8 Merge pull request 'feature/v13-corrections' (#794) from feature/v13-corrections into v13
All checks were successful
Release Creation / build (release) Successful in 2m45s
Reviewed-on: https, #794
2026-01-19 21:44:59 +01:00
fa30705989 Affichage de l'XP des sorts et caractéristiques 2026-01-17 03:45:42 +01:00
04f550dd21 Fix jet de résistance V2
sans cométence s'il n'y a pas de sélection
2026-01-16 08:47:51 +01:00
850cae3979 Attaques V2 depuis onglet combat 2026-01-16 08:47:50 +01:00
7b514d5159 Background arme inutilisable 2026-01-14 23:55:03 +01:00
d78ede4f59 Fix missing import 2026-01-14 23:47:01 +01:00
185 changed files with 1756 additions and 1446 deletions

View File

@@ -1,12 +1,69 @@
# 13.0
## 13.0.36 - Les rêveries d'Illisys
- Corrections v14
- les attaques à distance n'empèchent plus la fenêtre d'attaque de s'ouvrir
- les commandes (/help, ...) fonctionnent en v14
- Les feuilles d'acteurs ne s'ouvrent plus lors d'un changement (par exemple en cas d'encaissement)
- Les jeux sont correctement affichés
- Ajout d'une gravité de blessure sur les encaissement d'entités
- Amélioration de champs numériques: ajout de min et max quand c'est utile
- correction pour cuisiner depuis l'équipement
- les boutons dans les listes d'équipement sont mieux affichés sans retour à la ligne
## 13.0.35 - Les travaux d'Illisys
- Correction du recul contre une entité de cauchemar (qui utilise le rêve comme force)
- Correction erreur lors de la suppression d'un objet d'un conteneur
- Meilleure gestion des messages publics/GM, en particulier pour les tirage dans les compendiums
- Filtrage des boutons pour les acteurs non personnages (pour éviter de faire manger l'auberge...)
## 13.0.34 - La saumuche d'Illysis
- la qualité des "improvisations du moment" se base sur le niveau du cuisinier
- l'appel au moral n'est pas affiché à l'ouverture d'une fenêtre de jets de sorts (ou de tâche intellectuelle)
- la difficulté variable de l'annulation de magie est bien prise en compte
- correction erreur lors de la suppression d'un objet d'un conteneur
## 13.0.33 - L'ébriété d'Illysis
- le stade éméché ne cause plus de perte d'endurance
## 13.0.32 - Le surpoids d'Illysis
- Le malus d'encombrement sur jet d'Agilité avec Natation ou Acrobatie peuvent être changés, et sont correctement arrondis
- L'ajustement de condition est plus visible sur les résultats de jets de dés
- Les blessures graves soignées ne font pas perdre d'endurance par round
- Les blessures et pertes correspondantes (vie, endurance, effets sonné, ...) s'affichent correctement
- la remise à neuf ne provoque pas d'erreur pour certains effets déjà supprimés
## 13.0.31 - Les choix multiples d'Illysis
- les défauts de caractéristique/difficulté des compétences ne sont pris que si aucun autre choix n'est fait
- lors d'une attaque à deux mains avec une arme à une ou deux mains, les dommages à deux mains sont bien utilisés
## 13.0.30 - Le pansement d'Illysis
- les soins d'un joueur à l'autre fonctionne de nouveau
- la fenêtre de jet de compétence s'ouvre avec la caractéristique et la difficulté par défaut
- on peut saisir des valeurs négatives au clavier en sélectionnant les conditions/difficultés
## 13.0.29 - Le tricorne d'Illysis
- gestion des attaques avec jets V2 depuis l'onglet de combat
- les jets de résistance en mode V2 fonctionnent sans sélection de compétence
- affichage de l'expérience correspondant aux sorts pour aider à la création
- affichage de l'équivallent d'expérience des caractéristiques
## 13.0.28 - La quadrature d'Illysis
- Les ajustements de portée sont calculés pour les attaques à distance
- L'appel au moral dans le tchat ne déplace plus les boutons d'appel à la chance
- Correction d'apparence V13
- la fenêtre de choix des status utilisés est affichée correctement
- la fenêtrre d'astrologir MJ est affichée correctement
- la fenêtre d'astrologie MJ est affichée correctement
## 13.0.27 - Les lunettes d'Illysis

View File

@@ -893,7 +893,7 @@ body {
max-width: 1.4rem;
max-height: 1.4rem;
border: 1px;
background: center / contain no-repeat url("../../icons/templates/icone_parchement_vierge.webp");
background: center / contain no-repeat url("../icons/templates/icone_parchement_vierge.webp");
}
.system-foundryvtt-reve-de-dragon .sheet-header .header-compteurs {
width: calc(60% - 110px - 1rem);
@@ -1120,49 +1120,27 @@ body {
text-align: left;
}
.system-foundryvtt-reve-de-dragon .equipement-nom {
flex-grow: 3;
flex-grow: 4;
flex-shrink: 2;
margin: 0;
justify-content: center;
text-align: left;
display: ruby;
}
.system-foundryvtt-reve-de-dragon .equipement-valeur {
margin: 0;
flex-grow: 1.5;
flex-grow: 1;
flex-shrink: 1;
text-align: center;
}
.system-foundryvtt-reve-de-dragon .equipement-detail {
margin: 0;
flex-grow: 1;
align-items: center;
justify-content: center;
text-align: center;
}
.system-foundryvtt-reve-de-dragon span.equipement-detail-buttons {
margin: 0;
flex-grow: 1.5;
flex-shrink: 1;
align-items: center;
justify-content: center;
text-align: center;
display: flex;
flex-direction: row;
}
.system-foundryvtt-reve-de-dragon .equipement-button {
margin: 0;
flex-grow: 0.5;
align-items: center;
justify-content: center;
text-align: center;
}
.system-foundryvtt-reve-de-dragon :is(.item-actions-controls, .equipement-actions) {
margin: 0;
flex-grow: 1.2;
align-items: end;
justify-content: flex-end;
text-align: right;
}
.system-foundryvtt-reve-de-dragon .liste-equipement :is(.equipement-actions, .item-actions-controls) {
flex-grow: 2;
min-width: max-content;
}
.system-foundryvtt-reve-de-dragon .blessure-control {
flex-grow: 1;
@@ -1526,9 +1504,20 @@ body {
.system-foundryvtt-reve-de-dragon .competence-list .item-controls.hidden-controls {
display: none !important;
}
.system-foundryvtt-reve-de-dragon .competence-header .item-actions-controls {
flex-shrink: 2;
flex-grow: 2;
}
.system-foundryvtt-reve-de-dragon .item-actions-controls,
.system-foundryvtt-reve-de-dragon .item-controls {
vertical-align: super;
margin: 0;
flex-grow: 1;
flex-shrink: 1;
align-items: end;
text-align: right;
min-width: max-content;
flex-basis: fit-content;
vertical-align: baseline;
}
.system-foundryvtt-reve-de-dragon .item-actions-controls img,
.system-foundryvtt-reve-de-dragon .item-controls img {
@@ -2379,8 +2368,9 @@ body {
}
.system-foundryvtt-reve-de-dragon .chat-inline-icon {
border: 0;
padding: 1px;
padding: 0 0.2rem;
vertical-align: text-top;
display: inline;
}
.system-foundryvtt-reve-de-dragon .actor-img-small {
max-width: 1.5rem;
@@ -2498,12 +2488,6 @@ body {
background: #1e1914;
border: 1px solid #482e1c;
}
.system-foundryvtt-reve-de-dragon #players {
border-image: url(../assets/ui/footer-button.webp) 10 repeat;
border-image-width: 4px;
border-image-outset: 0px;
background: #1e1914;
}
.system-foundryvtt-reve-de-dragon #navigation #scene-list .scene.nav-item.active {
background: #482e1c;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 136 KiB

BIN
icons/creatures/glou_t.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -1,5 +1,6 @@
<h3>Joyeuses fêtes</h3>
<h3>L'oeuf de Dragon</h3>
<p>
VincentVK, LeRatierBretonnien et toute l'équipe de Scriptrarium vous
souhaitent de joyeuses et oniriques fêtes !
On raconte que si le premier Vaisseau, on trouve un oeuf couvé par
un lapin, il faut bien s'occuper dudit lapin, car quatre mois plus tard
pourrait bien éclore un dragon!
</p>

View File

@@ -136,7 +136,7 @@
max-height: 1.4rem;
border: 1px;
background: center / contain no-repeat
url("../../icons/templates/icone_parchement_vierge.webp");
url("../icons/templates/icone_parchement_vierge.webp");
}
.sheet-header .header-compteurs {
@@ -393,49 +393,27 @@
text-align: left;
}
.equipement-nom {
flex-grow: 3;
flex-grow: 4;
flex-shrink: 2;
margin: 0;
justify-content: center;
text-align: left;
display: ruby;
}
.equipement-valeur {
margin: 0;
flex-grow: 1.5;
flex-grow: 1;
flex-shrink: 1;
text-align: center;
}
.equipement-detail {
margin: 0;
flex-grow: 1;
align-items: center;
justify-content: center;
text-align: center;
}
span.equipement-detail-buttons {
margin: 0;
flex-grow: 1.5;
flex-shrink: 1;
align-items: center;
justify-content: center;
text-align: center;
display: flex;
flex-direction: row;
}
.equipement-button {
margin: 0;
flex-grow: 0.5;
align-items: center;
justify-content: center;
text-align: center;
}
:is(.item-actions-controls, .equipement-actions) {
margin: 0;
flex-grow: 1.2;
align-items: end;
justify-content: flex-end;
text-align: right;
}
.liste-equipement :is(.equipement-actions, .item-actions-controls) {
flex-grow: 2;
min-width: max-content;
}
.blessure-control {
@@ -848,12 +826,20 @@
.competence-list .item-controls.hidden-controls {
display: none !important;
}
.competence-header .item-actions-controls{
flex-shrink: 2;
flex-grow: 2;
}
.item-actions-controls,
.item-controls {
vertical-align: super;
// a {
// }
margin: 0;
flex-grow: 1;
flex-shrink: 1;
align-items: end;
text-align: right;
min-width: max-content;
flex-basis: fit-content;
vertical-align: baseline;
img {
vertical-align: text-bottom;
display: inline;
@@ -1776,8 +1762,9 @@
}
.chat-inline-icon {
border: 0;
padding: 1px;
padding: 0 0.2rem;
vertical-align: text-top;
display: inline;
}
.actor-img-small {
@@ -1911,13 +1898,6 @@
border: 1px solid rgba(72, 46, 28, 1);
}
#players {
border-image: url(../assets/ui/footer-button.webp) 10 repeat;
border-image-width: 4px;
border-image-outset: 0px;
background: rgba(30, 25, 20, 1);
}
#navigation #scene-list .scene.nav-item.active {
background: rgba(72, 46, 28, 1);
}

View File

@@ -19,6 +19,7 @@ import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js";
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
import { MORAL } from "./moral/apprecier.mjs";
import { RdDItemSort } from "./item-sort.js";
/* -------------------------------------------- */
/**
@@ -50,8 +51,9 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
foundry.utils.mergeObject(formData.calc, {
surenc: this.actor.computeMalusSurEncombrement(),
surprise: RdDBonus.find(this.actor.getSurprise(false)).label,
resumeBlessures: this.actor.computeResumeBlessure(this.actor.system.blessures),
blessures: this.actor.computeResumeBlessure(this.actor.system.blessures),
caracTotal: RdDCarac.computeTotal(this.actor.system.carac, this.actor.system.beaute),
caracTotalXp: RdDCarac.computeTotalXp(this.actor.system.carac, this.actor.system.beaute),
surEncombrementMessage: this.actor.isSurenc() ? "Sur-Encombrement!" : "",
malusArmure: this.actor.getMalusArmure()
})
@@ -61,9 +63,13 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
if (formData.type == ACTOR_TYPES.personnage) {
formData.options.mainsDirectrices = MAINS_DIRECTRICES;
formData.byCateg = Misc.classify(formData.competences, it => it.system.categorie)
formData.calc.comptageArchetype = RdDItemCompetence.computeResumeArchetype(formData.competences);
formData.calc.competenceXPTotal = RdDItemCompetence.computeTotalXP(formData.competences);
formData.calc.fatigue = RdDUtility.calculFatigueHtml(formData.system.sante.fatigue.value, formData.system.sante.endurance.max);
foundry.utils.mergeObject(formData.calc, {
comptageArchetype: RdDItemCompetence.computeResumeArchetype(formData.competences),
competenceXPTotal: RdDItemCompetence.computeTotalXP(formData.competences),
sortsXPTotal: RdDItemSort.computeTotalXP(this.actor.itemTypes[ITEM_TYPES.sort]),
fatigue: RdDUtility.calculFatigueHtml(formData.system.sante.fatigue.value, formData.system.sante.endurance.max)
})
formData.competences.forEach(item => {
item.system.isHidden = this.options.recherche
@@ -273,7 +279,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
// On pts de reve change
this.html.find('.pointsreve-value').change(async event => await this.actor.update({ "system.reve.reve.value": event.currentTarget.value }))
this.html.find('.seuil-reve-value').change(async event => await this.actor.setPointsDeSeuil(event.currentTarget.value))
this.html.find('.seuil-reve-value').change(async event => await this.actor.update({ "system.reve.seuil.value": event.currentTarget.value }))
this.html.find('.stress-test').click(async event => await this.actor.transformerStress())
this.html.find('.moral-malheureux').click(async event => await this.actor.jetDeMoral(MORAL.MALHEUREUX))

View File

@@ -175,7 +175,7 @@ export class RdDActor extends RdDBaseActorSang {
}
isForceInsuffisante(forceRequise) {
const force = parseInt(this.system.carac.force.value)
const force = parseInt(this.getForce())
return forceRequise > force
}
@@ -418,7 +418,7 @@ export class RdDActor extends RdDBaseActorSang {
}
async _recupereMoralChateauDormant(message) {
await this.update({ 'system.compteurs.bonmoments': [] }, { render: false })
await this.update({ 'system.compteurs.bonmoments': [] })
if (!ReglesOptionnelles.isUsing("recuperation-moral")) { return }
@@ -454,7 +454,7 @@ export class RdDActor extends RdDBaseActorSang {
blessures
})));
await this.supprimerBlessures(it => it.system.gravite <= 0);
await this.supprimerBlessures(it => it.system.gravite <= 0)
}
/* -------------------------------------------- */
@@ -498,18 +498,18 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async remiseANeuf() {
await this.removeEffects(e => !e.statuses?.has(STATUSES.StatusDemiReve))
await this.supprimerBlessures(it => true)
await this.update({
'system.sante.endurance.value': this.system.sante.endurance.max,
'system.sante.vie.value': this.system.sante.vie.max,
'system.sante.fatigue.value': 0,
'system.compteurs.ethylisme': { value: 1, nb_doses: 0, jet_moral: false }
})
await this.removeEffects(e => !e.statuses?.has(STATUSES.StatusDemiReve));
await this.supprimerBlessures(it => true);
await ChatMessage.create({
whisper: ChatUtility.getOwners(this),
content: 'Remise à neuf de ' + this.name
});
})
}
/* -------------------------------------------- */
@@ -689,8 +689,9 @@ export class RdDActor extends RdDBaseActorSang {
message.content += `<br>Vous n'avez bu que ${eauConsomme} doses de liquide pour une soif de ${sustNeeded}, vous avez soif!
La soif devrait vous faire ${perte} points d'endurance non récupérables, notez le cumul de côté et ajustez l'endurance`;
}
await this.updateCompteurValue('sust', 0);
await this.updateCompteurValue('eau', 0);
await this.update({ 'system.compteurs.sust.value': 0 });
await this.update({ 'system.compteurs.eau.value': 0 });
}
/* -------------------------------------------- */
@@ -753,25 +754,25 @@ export class RdDActor extends RdDBaseActorSang {
updates[`system.compteurs.chance.value`] = to
}
}
let selectedCarac = this.findCaracByName(caracName);
let selectedCarac = this.findCaracByName(caracName)
const from = selectedCarac.value
updates[`system.carac.${caracName}.value`] = to;
await this.update(updates, { noHook: true });
await ExperienceLog.add(this, XP_TOPIC.CARAC, from, to, caracName);
updates[`system.carac.${caracName}.value`] = to
await this.update(updates, { noHook: true })
await ExperienceLog.add(this, XP_TOPIC.CARAC, from, to, caracName)
}
/* -------------------------------------------- */
async updateCaracXP(caracName, to) {
if (caracName == 'Taille') {
return;
return
}
let selectedCarac = this.findCaracByName(caracName);
if (!selectedCarac.derivee) {
const from = Number(selectedCarac.xp);
await this.update({ [`system.carac.${caracName}.xp`]: to });
await ExperienceLog.add(this, XP_TOPIC.XPCARAC, from, to, caracName);
const from = Number(selectedCarac.xp)
await this.update({ [`system.carac.${caracName}.xp`]: to })
await ExperienceLog.add(this, XP_TOPIC.XPCARAC, from, to, caracName)
}
this.checkCaracXP(caracName);
this.checkCaracXP(caracName)
}
/* -------------------------------------------- */
@@ -792,9 +793,9 @@ export class RdDActor extends RdDBaseActorSang {
}
carac.xp = toXp;
carac.value = toValue;
await this.update({ [`system.carac.${caracName}`]: carac });
await ExperienceLog.add(this, XP_TOPIC.XPCARAC, fromXp, toXp, caracName);
await ExperienceLog.add(this, XP_TOPIC.CARAC, fromValue, toValue, caracName);
await this.update({ [`system.carac.${caracName}`]: carac })
await ExperienceLog.add(this, XP_TOPIC.XPCARAC, fromXp, toXp, caracName)
await ExperienceLog.add(this, XP_TOPIC.CARAC, fromValue, toValue, caracName)
}
}
@@ -813,7 +814,7 @@ export class RdDActor extends RdDBaseActorSang {
await competence.update({
"system.xp": toXp,
"system.niveau": toNiveau,
}, { render: false })
})
await ExperienceLog.add(this, XP_TOPIC.XP, fromXp, toXp, competence.name);
await ExperienceLog.add(this, XP_TOPIC.NIVEAU, fromNiveau, toNiveau, competence.name);
}
@@ -822,35 +823,35 @@ export class RdDActor extends RdDBaseActorSang {
async updateCompetenceStress(idOrName) {
const competence = this.getCompetence(idOrName);
if (!competence) {
return;
return
}
const fromXp = competence.system.xp;
const fromXpStress = this.system.compteurs.experience.value;
const fromNiveau = Number(competence.system.niveau);
const xpSuivant = RdDItemCompetence.getCompetenceNextXp(fromNiveau);
const xpRequis = xpSuivant - fromXp;
const fromXp = competence.system.xp
const fromXpStress = this.system.compteurs.experience.value
const fromNiveau = Number(competence.system.niveau)
const xpSuivant = RdDItemCompetence.getCompetenceNextXp(fromNiveau)
const xpRequis = xpSuivant - fromXp
if (fromXpStress <= 0 || fromNiveau >= competence.system.niveau_archetype) {
ui.notifications.info(`La compétence ne peut pas augmenter!
stress disponible: ${fromXpStress}
expérience requise: ${xpRequis}
niveau : ${fromNiveau}
archétype : ${competence.system.niveau_archetype}`);
archétype : ${competence.system.niveau_archetype}`)
return
}
const xpUtilise = Math.max(0, Math.min(fromXpStress, xpRequis));
const gainNiveau = (xpUtilise >= xpRequis || xpRequis <= 0) ? 1 : 0;
const toNiveau = fromNiveau + gainNiveau;
const newXp = gainNiveau > 0 ? Math.max(fromXp - xpSuivant, 0) : (fromXp + xpUtilise);
const xpUtilise = Math.max(0, Math.min(fromXpStress, xpRequis))
const gainNiveau = (xpUtilise >= xpRequis || xpRequis <= 0) ? 1 : 0
const toNiveau = fromNiveau + gainNiveau
const newXp = gainNiveau > 0 ? Math.max(fromXp - xpSuivant, 0) : (fromXp + xpUtilise)
await competence.update({
"system.xp": newXp,
"system.niveau": toNiveau,
}, { render: false })
const toXpStress = Math.max(0, fromXpStress - xpUtilise);
await this.update({ "system.compteurs.experience.value": toXpStress });
})
const toXpStress = Math.max(0, fromXpStress - xpUtilise)
await this.update({ "system.compteurs.experience.value": toXpStress })
await ExperienceLog.add(this, XP_TOPIC.TRANSFORM, fromXpStress, toXpStress, `Dépense stress`);
await ExperienceLog.add(this, XP_TOPIC.XP, fromXp, newXp, competence.name);
await ExperienceLog.add(this, XP_TOPIC.NIVEAU, fromNiveau, toNiveau, competence.name);
await ExperienceLog.add(this, XP_TOPIC.TRANSFORM, fromXpStress, toXpStress, `Dépense stress`)
await ExperienceLog.add(this, XP_TOPIC.XP, fromXp, newXp, competence.name)
await ExperienceLog.add(this, XP_TOPIC.NIVEAU, fromNiveau, toNiveau, competence.name)
}
/* -------------------------------------------- */
@@ -860,8 +861,8 @@ export class RdDActor extends RdDBaseActorSang {
const toNiveau = compValue ?? RdDItemCompetence.getNiveauBase(competence.system.categorie, competence.getCategories());
this.notifyCompetencesTronc(competence, toNiveau);
const fromNiveau = competence.system.niveau;
await competence.update({ 'system.niveau': toNiveau }, { render: true })
await ExperienceLog.add(this, XP_TOPIC.NIVEAU, fromNiveau, toNiveau, competence.name, true);
await competence.update({ 'system.niveau': toNiveau })
await ExperienceLog.add(this, XP_TOPIC.NIVEAU, fromNiveau, toNiveau, competence.name, true)
}
}
@@ -882,11 +883,13 @@ export class RdDActor extends RdDBaseActorSang {
async updateCompetenceXP(idOrName, toXp) {
let competence = this.getCompetence(idOrName);
if (competence) {
if (isNaN(toXp) || typeof (toXp) != 'number') toXp = 0;
const fromXp = competence.system.xp;
this.checkCompetenceXP(idOrName, toXp);
await competence.update({ 'system.xp': toXp }, { render: false })
await ExperienceLog.add(this, XP_TOPIC.XP, fromXp, toXp, competence.name, true);
if (isNaN(toXp) || typeof (toXp) != 'number') {
toXp = 0
}
const fromXp = competence.system.xp
this.checkCompetenceXP(idOrName, toXp)
await competence.update({ 'system.xp': toXp })
await ExperienceLog.add(this, XP_TOPIC.XP, fromXp, toXp, competence.name, true)
if (toXp > fromXp) {
RdDUtility.checkThanatosXP(competence)
}
@@ -897,10 +900,12 @@ export class RdDActor extends RdDBaseActorSang {
async updateCompetenceXPSort(idOrName, toXpSort) {
let competence = this.getCompetence(idOrName);
if (competence) {
if (isNaN(toXpSort) || typeof (toXpSort) != 'number') toXpSort = 0;
const fromXpSort = competence.system.xp_sort;
await competence.update({ 'system.xp_sort': toXpSort }, { render: false })
await ExperienceLog.add(this, XP_TOPIC.XPSORT, fromXpSort, toXpSort, competence.name, true);
if (isNaN(toXpSort) || typeof (toXpSort) != 'number') {
toXpSort = 0
}
const fromXpSort = competence.system.xp_sort
await competence.update({ 'system.xp_sort': toXpSort })
await ExperienceLog.add(this, XP_TOPIC.XPSORT, fromXpSort, toXpSort, competence.name, true)
if (toXpSort > fromXpSort) {
RdDUtility.checkThanatosXP(competence)
}
@@ -917,25 +922,25 @@ export class RdDActor extends RdDBaseActorSang {
async deleteExperienceLog(from, count) {
if (from >= 0 && count > 0) {
let expLog = foundry.utils.duplicate(this.system.experiencelog);
expLog.splice(from, count);
await this.update({ [`system.experiencelog`]: expLog });
let expLog = foundry.utils.duplicate(this.system.experiencelog)
expLog.splice(from, count)
await this.update({ [`system.experiencelog`]: expLog })
}
}
/* -------------------------------------------- */
async updateCompteurValue(fieldName, to) {
const from = this.system.compteurs[fieldName].value
await this.update({ [`system.compteurs.${fieldName}.value`]: to });
await this.addStressExperienceLog(fieldName, from, to, fieldName, true);
await this.update({ [`system.compteurs.${fieldName}.value`]: to })
await this.addStressExperienceLog(fieldName, from, to, fieldName, true)
}
/* -------------------------------------------- */
async addCompteurValue(fieldName, add, raison) {
let from = this.system.compteurs[fieldName].value;
const to = Number(from) + Number(add);
await this.update({ [`system.compteurs.${fieldName}.value`]: to });
await this.addStressExperienceLog(fieldName, from, to, raison);
let from = this.system.compteurs[fieldName].value
const to = Number(from) + Number(add)
await this.update({ [`system.compteurs.${fieldName}.value`]: to })
await this.addStressExperienceLog(fieldName, from, to, raison)
}
async addStressExperienceLog(topic, from, to, raison, manuel) {
@@ -948,35 +953,22 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
async distribuerStress(compteur, stress, motif) {
async distribuerStress(compteur, valeur, motif) {
if (game.user.isGM && this.hasPlayerOwner) {
switch (compteur) {
case 'stress': case 'experience':
await this.addCompteurValue(compteur, stress, motif);
const message = `${this.name} a reçu ${stress} points ${compteur == 'stress' ? "de stress" : "d'expérience"} (raison : ${motif})`;
ui.notifications.info(message);
game.users.players.filter(player => player.active && player.character?.id == this.id)
await this.addCompteurValue(compteur, valeur, motif);
const message = `${this.name} a reçu ${valeur} points ${compteur == 'stress' ? "de stress" : "d'expérience"} (raison : ${motif})`;
game.users.players.filter(player => this.testUserPermission(player, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER))
.forEach(player => ChatUtility.notifyUser(player.id, 'info', message));
}
}
}
/* -------------------------------------------- */
async updateAttributeValue(fieldName, fieldValue) {
await this.update({ [`system.attributs.${fieldName}.value`]: fieldValue });
}
/* -------------------------------------------- */
ethylisme() {
return this.system.compteurs.ethylisme?.value ?? 1;
}
malusEthylisme() {
return Math.min(0, this.ethylisme())
}
isAlcoolise() {
return this.ethylisme() < 1
}
ethylisme() { return this.system.compteurs.ethylisme?.value ?? 1 }
malusEthylisme() { return Math.min(0, this.ethylisme()) }
isAlcoolise() { return this.ethylisme() < 1 }
/* -------------------------------------------- */
async actionRefoulement(item) {
@@ -997,15 +989,15 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async ajouterRefoulement(value = 1, refouler) {
let refoulement = this.system.reve.refoulement.value + value;
const roll = new Roll("1d20");
await roll.evaluate();
await roll.toMessage({ flavor: `${this.name} refoule ${refouler} pour ${value} points de refoulement (total: ${refoulement})` });
let refoulement = this.system.reve.refoulement.value + value
const roll = new Roll("1d20")
await roll.evaluate()
await roll.toMessage({ flavor: `${this.name} refoule ${refouler} pour ${value} points de refoulement (total: ${refoulement})` })
if (roll.total <= refoulement) {
refoulement = 0;
await this.ajouterSouffle({ chat: true });
refoulement = 0
await this.ajouterSouffle({ chat: true })
}
await this.update({ "system.reve.refoulement.value": refoulement });
await this.update({ "system.reve.refoulement.value": refoulement })
return roll;
}
@@ -1013,14 +1005,14 @@ export class RdDActor extends RdDBaseActorSang {
async ajouterSouffle(options = { chat: false }) {
let souffle = await RdDRollTables.getSouffle()
//souffle.id = undefined; //TBC
await this.createEmbeddedDocuments('Item', [souffle]);
await this.createEmbeddedDocuments('Item', [souffle])
if (options.chat) {
ChatMessage.create({
whisper: ChatUtility.getOwners(this),
content: this.name + " subit un Souffle de Dragon : " + souffle.name
});
})
}
return souffle;
return souffle
}
/* -------------------------------------------- */
@@ -1028,7 +1020,7 @@ export class RdDActor extends RdDBaseActorSang {
let queue;
if (this.system.reve.reve.thanatosused) {
queue = await RdDRollTables.getOmbre();
await this.update({ "system.reve.reve.thanatosused": false });
await this.update({ "system.reve.reve.thanatosused": false })
}
else {
queue = await RdDRollTables.getQueue();
@@ -1038,7 +1030,7 @@ export class RdDActor extends RdDBaseActorSang {
ChatMessage.create({
whisper: ChatUtility.getOwners(this),
content: this.name + " subit une Queue de Dragon : " + queue.name
});
})
}
return queue;
}
@@ -1074,13 +1066,13 @@ export class RdDActor extends RdDBaseActorSang {
}
const donHR = await RdDItemTete.teteDonDeHautReve()
if (donHR) {
this.createEmbeddedDocuments('Item', [donHR.toObject()])
await this.createEmbeddedDocuments('Item', [donHR.toObject()])
}
}
async addSortReserve(item) {
if (item?.type == ITEM_TYPES.sort && !item.system.isrituel) {
this.$createSortReserve(item)
await this.$createSortReserve(item)
return
}
const selectSortReserve = {
@@ -1091,9 +1083,9 @@ export class RdDActor extends RdDBaseActorSang {
DialogSelect.select(selectSortReserve, sort => this.$createSortReserve(sort))
}
$createSortReserve(sort) {
async $createSortReserve(sort) {
const ptReve = Number.isInteger(sort.system.ptreve) ? Number(sort.system.ptreve) : Number(sort.system.ptreve.match(/\d+/))
this.createEmbeddedDocuments("Item",
await this.createEmbeddedDocuments("Item",
[{
type: ITEM_TYPES.sortreserve,
name: sort.name,
@@ -1141,7 +1133,7 @@ export class RdDActor extends RdDBaseActorSang {
async addTMRRencontre(currentRencontre) {
const toCreate = currentRencontre.toObject();
console.log('actor.addTMRRencontre(', toCreate, ')');
this.createEmbeddedDocuments('Item', [toCreate]);
await this.createEmbeddedDocuments('Item', [toCreate]);
}
/* -------------------------------------------- */
@@ -1161,26 +1153,17 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
async regainPointDeSeuil() {
const seuil = Misc.toInt(this.system.reve.seuil.value);
const seuilMax = Misc.toInt(this.system.carac.reve.value)
async recuperationSeuilReve() {
const value = Misc.toInt(this.system.reve.seuil.value);
const max = Misc.toInt(this.system.carac.reve.value)
+ 2 * EffetsDraconiques.countAugmentationSeuil(this);
if (seuil < seuilMax) {
await this.setPointsDeSeuil(Math.min(seuil + 1, seuilMax));
if (value < max) {
const nouveauSeuil = Math.min(value + 1, max);
await this.update({ "system.reve.seuil.value": nouveauSeuil });
}
}
/* -------------------------------------------- */
async setPointsDeSeuil(seuil) {
await this.update({ "system.reve.seuil.value": seuil });
}
/* -------------------------------------------- */
async setPointsDeChance(chance) {
await this.updateCompteurValue("chance", chance);
}
async jetEndurance(resteEndurance = undefined) {
const result = super.jetEndurance(resteEndurance);
if (result.jetEndurance == 1) {
@@ -1191,13 +1174,9 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
getSConst() { return RdDCarac.calculSConst(this.getConstitution()) }
async ajoutXpConstitution(xp) {
await this.update({ "system.carac.constitution.xp": Misc.toInt(this.system.carac.constitution.xp) + xp });
}
async _gainXpConstitutionJetEndurance() {
await this.ajoutXpConstitution(1); // +1 XP !
await this.updateCaracXP('constitution', Misc.toInt(this.system.carac.constitution.xp) + 1)
return `${this.name} a obtenu 1 sur son Jet d'Endurance et a gagné 1 point d'Expérience en Constitution. Ce point d'XP a été ajouté automatiquement.`;
}
@@ -1234,27 +1213,25 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
async moralIncDec(ajustementMoral, bonmoment = "") {
if (ajustementMoral != 0) {
if (ajustementMoral > 0 && bonmoment != "" && bonmoment != undefined) {
const bonmoments = [...this.system.compteurs.bonmoments, bonmoment]
await this.update({ 'system.compteurs.bonmoments': bonmoments }, { render: false })
async moralIncDec(ajustement, bonmoment = "") {
let moral = parseInt(this.system.compteurs.moral.value)
if (ajustement != 0) {
if (ajustement > 0 && bonmoment != "" && bonmoment != undefined) {
await this.update({ 'system.compteurs.bonmoments': [...this.system.compteurs.bonmoments, bonmoment] })
}
const startMoral = parseInt(this.system.compteurs.moral.value)
const moralTheorique = startMoral + ajustementMoral
const moralTheorique = moral + ajustement
if (moralTheorique > 3) { // exaltation
const ajoutExaltation = moralTheorique - 3
const exaltation = parseInt(this.system.compteurs.exaltation.value) + ajoutExaltation
await this.updateCompteurValue('exaltation', exaltation)
const exaltation = parseInt(this.system.compteurs.exaltation.value) + moralTheorique - 3
await this.update({ 'system.compteurs.exaltation.value': exaltation })
}
if (moralTheorique < -3) { // dissolution
const ajoutDissolution = -3 - moralTheorique
const dissolution = parseInt(this.system.compteurs.dissolution.value) + ajoutDissolution
await this.updateCompteurValue('dissolution', dissolution)
const dissolution = parseInt(this.system.compteurs.dissolution.value) - 3 - moralTheorique
await this.update({ 'system.compteurs.dissolution.value': dissolution })
}
await this.updateCompteurValue('moral', Math.max(-3, Math.min(moralTheorique, 3)));
moral = Math.max(-3, Math.min(moralTheorique, 3));
await this.update({ 'system.compteurs.moral.value': moral })
}
return this.system.compteurs.moral.value;
return moral
}
/* -------------------------------------------- */
@@ -1386,7 +1363,7 @@ export class RdDActor extends RdDBaseActorSang {
async manger(item, doses, options = { diminuerQuantite: true }) {
const sust = item.system.sust
if (sust > 0) {
await this.updateCompteurValue('sust', RdDActor.$calculNewSust(this.system.compteurs.sust.value, sust, doses));
await this.update({ 'system.compteurs.sust.value': RdDActor.$calculNewSust(this.system.compteurs.sust.value, sust, doses) })
}
await item.diminuerQuantite(doses, options);
}
@@ -1394,9 +1371,9 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async boire(item, doses, options = { diminuerQuantite: true }) {
const desaltere = item.system.desaltere;
if (desaltere > 0) {
await this.updateCompteurValue('eau', RdDActor.$calculNewSust(this.system.compteurs.eau.value, desaltere, doses));
const eau = item.system.desaltere
if (eau > 0) {
await this.update({ 'system.compteurs.eau.value': RdDActor.$calculNewSust(this.system.compteurs.eau.value, eau, doses) })
}
if (item.isAlcool()) {
for (let i = 0; i < doses; i++) {
@@ -1421,6 +1398,7 @@ export class RdDActor extends RdDBaseActorSang {
actor: this,
vie: this.system.sante.vie.max,
alcool: alcool,
perteEndurance: 0,
jetVie: {
forceAlcool: forceAlcool,
nbDoses: nbDoses,
@@ -1433,7 +1411,7 @@ export class RdDActor extends RdDBaseActorSang {
}
await RdDResolutionTable.rollData(ethylismeData.jetVie);
this.gererExperience(ethylismeData.jetVie);
this.ajoutExperience(ethylismeData.jetVie);
RollDataAjustements.calcul(ethylismeData.jetVie, this);
if (ethylismeData.jetVie.rolled.isSuccess) {
ethylisme.nb_doses++;
@@ -1441,8 +1419,9 @@ export class RdDActor extends RdDBaseActorSang {
ethylisme.value = Math.max(ethylisme.value - 1, -7);
ethylisme.nb_doses = 0;
let perte = await RdDDice.rollTotal("1d6");
ethylismeData.perteEndurance = await this.santeIncDec("endurance", -perte);
if (ethylisme.value > 0) {
ethylismeData.perteEndurance = await this.santeIncDec("endurance", -(await RdDDice.rollTotal("1d6")))
}
if (!ethylisme.jet_moral) {
ethylismeData.jetMoral = await this._jetDeMoral(MORAL.HEUREUX, "Ethylisme");
@@ -1465,7 +1444,7 @@ export class RdDActor extends RdDBaseActorSang {
finalLevel: Number(ethylisme.value) + Number(this.system.compteurs.moral.value)
}
await RdDResolutionTable.rollData(ethylismeData.jetVolonte);
this.gererExperience(ethylismeData.jetVolonte);
this.ajoutExperience(ethylismeData.jetVolonte);
RollDataAjustements.calcul(ethylismeData.jetVolonte, this);
}
}
@@ -1521,13 +1500,12 @@ export class RdDActor extends RdDBaseActorSang {
const toStress = Math.max(fromStress - stressRollData.perte - 1, 0);
const fromXpSress = Number(this.system.compteurs.experience.value);
const toXpStress = fromXpSress + Number(stressRollData.xp);
const updates = {
await this.update({
"system.compteurs.stress.value": toStress,
"system.compteurs.experience.value": toXpStress,
"system.compteurs.dissolution.value": dissolution - perteDissolution,
"system.compteurs.exaltation.value": 0
}
await this.update(updates);
})
await ExperienceLog.add(this, XP_TOPIC.STRESS, fromStress, toStress, 'Transformation')
await ExperienceLog.add(this, XP_TOPIC.TRANSFORM, fromXpSress, toXpStress, 'Transformation')
}
@@ -1560,21 +1538,6 @@ export class RdDActor extends RdDBaseActorSang {
return 0;
}
/* -------------------------------------------- */
createCallbackExperience() {
return {
action: r => this.appliquerAjoutExperience(r)
};
}
/* -------------------------------------------- */
createCallbackAppelAuMoral() { /* Si l'appel au moral est utilisé, on l'affiche dans le chat et on diminue éventuellement le moral */
return {
action: r => this.appliquerAppelMoral(r)
};
}
/* -------------------------------------------- */
isCaracMax(code) {
return RdDItemRace.isRacialMax(this, code)
@@ -1608,38 +1571,11 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async checkCompetenceXP(compName, newXP, display = true) {
let compData = this.getCompetence(compName);
if (compData && newXP && newXP == compData.system.xp) { // Si édition, mais sans changement XP
return;
}
newXP = (newXP) ? newXP : compData.system.xp;
if (compData && newXP > 0) {
let xpNeeded = RdDItemCompetence.getCompetenceNextXp(compData.system.niveau + 1);
if (newXP >= xpNeeded) {
let newCompData = foundry.utils.duplicate(compData);
newCompData.system.niveau += 1;
newCompData.system.xp = newXP;
let checkXp = {
alias: this.getAlias(),
competence: newCompData.name,
niveau: newCompData.system.niveau,
xp: newCompData.system.xp,
archetype: newCompData.system.niveau_archetype,
archetypeWarning: newCompData.system.niveau > compData.system.niveau_archetype
}
if (display) {
ChatMessage.create({
whisper: ChatUtility.getOwners(this),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-competence-xp.hbs`, checkXp)
});
}
return checkXp;
}
}
return this.getCompetence(compName)?.checkCompetenceXP( newXP, display)
}
/* -------------------------------------------- */
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') {
async ajoutExperience(rollData, hideChatMessage = 'show') {
if (!rollData.rolled.isPart ||
rollData.finalLevel >= 0 ||
game.settings.get("core", "rollMode") == 'selfroll' ||
@@ -1805,30 +1741,30 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async _rollUnSortResult(rollData) {
let rolled = rollData.rolled;
let selectedSort = rollData.selectedSort;
let rolled = rollData.rolled
let selectedSort = rollData.selectedSort
rollData.isSortReserve = rollData.mettreEnReserve && !selectedSort.system.isrituel;
rollData.isSortReserve = rollData.mettreEnReserve && !selectedSort.system.isrituel
rollData.show = {}
rollData.depenseReve = Number(selectedSort.system.ptreve_reel);
rollData.depenseReve = Number(selectedSort.system.ptreve_reel)
if (rollData.competence.name.includes('Thanatos')) { // Si Thanatos
await this.update({ "system.reve.reve.thanatosused": true });
await this.update({ "system.reve.reve.thanatosused": true })
}
let reveActuel = parseInt(this.system.reve.reve.value)
if (rolled.isSuccess) { // Réussite du sort !
if (rolled.isPart) {
rollData.depenseReve = Math.max(Math.floor(rollData.depenseReve / 2), 1);
rollData.depenseReve = Math.max(Math.floor(rollData.depenseReve / 2), 1)
}
if (rollData.isSortReserve) {
rollData.depenseReve++;
rollData.depenseReve++
}
if (reveActuel > rollData.depenseReve) {
// Incrémenter/gére le bonus de case
RdDItemSort.incrementBonusCase(this, selectedSort, rollData.tmr.coord);
RdDItemSort.incrementBonusCase(this, selectedSort, rollData.tmr.coord)
if (rollData.isSortReserve) {
await this.sortMisEnReserve(selectedSort, rollData.competence, rollData.tmr.coord, Number(selectedSort.system.ptreve_reel));
await this.sortMisEnReserve(selectedSort, rollData.competence, rollData.tmr.coord, Number(selectedSort.system.ptreve_reel))
}
else {
console.log('lancement de sort', rollData.selectedSort)
@@ -1853,16 +1789,15 @@ export class RdDActor extends RdDBaseActorSang {
}
}
reveActuel = Math.max(reveActuel - rollData.depenseReve, 0);
await this.update({ "system.reve.reve.value": reveActuel });
await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-sort.hbs');
reveActuel = Math.max(reveActuel - rollData.depenseReve, 0)
await this.update({ "system.reve.reve.value": reveActuel })
await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-sort.hbs')
if (reveActuel == 0) { // 0 points de reve
ChatMessage.create({ content: this.name + " est réduit à 0 Points de Rêve, et tombe endormi !" });
ChatMessage.create({ content: this.name + " est réduit à 0 Points de Rêve, et tombe endormi !" })
}
if (!rollData.isSortReserve || !rolled.isSuccess) {
this.tmrApp?.close();
this.tmrApp?.close()
}
}
@@ -1891,16 +1826,11 @@ export class RdDActor extends RdDBaseActorSang {
};
RollDataAjustements.calcul(rollData, this);
await RdDResolutionTable.rollData(rollData);
this.gererExperience(rollData);
this.ajoutExperience(rollData);
await RdDRollResult.displayRollData(rollData, this)
return rollData.rolled;
}
/* -------------------------------------------- */
gererExperience(rollData) {
this.createCallbackExperience().action(rollData);
}
/* -------------------------------------------- */
async creerTacheDepuisLivre(item, options = { renderSheet: true }) {
const nomTache = "Lire " + item.name;
@@ -2228,12 +2158,11 @@ export class RdDActor extends RdDBaseActorSang {
let destinee = this.system.compteurs.destinee?.value ?? 0;
if (destinee > 0) {
ChatMessage.create({ content: `<span class="rdd-roll-part">${this.name} a fait appel à la Destinée !</span>` });
destinee--;
await this.updateCompteurValue("destinee", destinee);
onSuccess();
await this.update({ 'system.compteurs.destinee.value ': destinee - 1 })
onSuccess()
}
else {
onEchec();
onEchec()
}
}
@@ -2294,7 +2223,7 @@ export class RdDActor extends RdDBaseActorSang {
const from = Number(xpData.competence.system.xp);
const to = from + xpData.xpCompetence;
await this.updateEmbeddedDocuments('Item', [{ _id: xpData.competence._id, 'system.xp': to }]);
xpData.checkComp = await this.checkCompetenceXP(xpData.competence.name, undefined, false);
xpData.checkComp = await this.checkCompetenceXP(xpData.competence.name, undefined, false)
await ExperienceLog.add(this, XP_TOPIC.XP, from, to, xpData.competence.name);
return [xpData]
}
@@ -2479,10 +2408,13 @@ export class RdDActor extends RdDBaseActorSang {
async quitterTMR(message, viewOnly, cumulFatigue) {
if (this.tmrApp) {
this.tmrApp = undefined
const appliquerFatigue = ReglesOptionnelles.isUsing("appliquer-fatigue");
await this.santeIncDec(
appliquerFatigue ? "fatigue" : "endurance",
(appliquerFatigue ? 1 : -1) * cumulFatigue)
if (ReglesOptionnelles.isUsing("appliquer-fatigue")) {
await this.santeIncDec("fatigue", cumulFatigue)
}
else {
await this.santeIncDec("endurance", - cumulFatigue)
}
if (!viewOnly) {
await this.supprimerSignesDraconiques(it => it.system.ephemere && it.system.duree == '1 round', { render: false })
await this.setEffect(STATUSES.StatusDemiReve, false)
@@ -2504,9 +2436,9 @@ export class RdDActor extends RdDBaseActorSang {
const blessure = blesse.blessuresASoigner().find(it => it.id == blessureId);
if (blessure) {
if (!blessure.system.premierssoins.done) {
const tache = await this.getTacheBlessure(blesse, blessure);
return await this.rollTache(tache.id, {
callbacks: [async r => await blesse.onRollTachePremiersSoins(blessureId, r, this.id)],
const tacheId = (await this.getTacheBlessure(blesse, blessure))?.id
return await this.rollTache(tacheId, {
callbacks: [async r => await blesse.callbackPremiersSoins(blessureId, r, this.id)],
title: 'Premiers soins', forced: true
});
}
@@ -2545,10 +2477,10 @@ export class RdDActor extends RdDBaseActorSang {
async equiperObjet(item) {
if (item?.isEquipable()) {
const isEquipe = !item.system.equipe;
await item.update({ "system.equipe": isEquipe });
await item.update({ "system.equipe": isEquipe })
this.computeEncTotal()
if (isEquipe)
this.verifierForceMin(item);
this.verifierForceMin(item)
}
}
@@ -2691,10 +2623,10 @@ export class RdDActor extends RdDBaseActorSang {
async setPointsCoeur(subActorId, coeurs, options = { immediat: false }) {
const newSuivants = foundry.utils.duplicate(this.system.subacteurs.suivants)
const amoureux = newSuivants.find(it => it.id == subActorId);
const amoureux = newSuivants.find(it => it.id == subActorId)
if (amoureux) {
amoureux[options.immediat ? 'coeur' : 'prochainCoeur'] = coeurs
await this.update({ 'system.subacteurs.suivants': newSuivants });
await this.update({ 'system.subacteurs.suivants': newSuivants })
}
}
@@ -2748,9 +2680,9 @@ export class RdDActor extends RdDBaseActorSang {
let alreadyPresent = dataArray.find(attached => attached.id == subActor.id);
if (!alreadyPresent) {
let newArray = [...dataArray, subActor]
await this.update({ [dataPath]: newArray });
await this.update({ [dataPath]: newArray })
} else {
ui.notifications.warn(dataName + " est déja attaché à " + this.name);
ui.notifications.warn(dataName + " est déja attaché à " + this.name)
}
}
@@ -2772,36 +2704,37 @@ export class RdDActor extends RdDBaseActorSang {
async deleteSubActeur(actorId) {
['vehicules', 'suivants', 'montures'].forEach(async type => {
const subList = this.system.subacteurs[type];
const subList = this.system.subacteurs[type]
if (subList.find(it => it.id == actorId)) {
let newList = subList.filter(it => it.id != actorId)
await this.update({ [`system.subacteurs.${type}`]: newList }, { renderSheet: false });
await this.update({ [`system.subacteurs.${type}`]: newList }, { render: false })
}
})
}
/* -------------------------------------------- */
async buildPotionGuerisonList(pointsGuerison) {
const pointsGuerisonInitial = pointsGuerison;
const blessures = this.filterItems(it => it.system.gravite > 0, 'blessure').sort(Misc.descending(it => it.system.gravite))
const pointsGuerisonInitial = pointsGuerison
const blessures = this.filterItems(it => it.system.gravite > 0, 'blessure')
.sort(Misc.descending(it => it.system.gravite))
const ids = []
const guerisonData = { list: [], pointsConsommes: 0 }
for (let blessure of blessures) {
if (pointsGuerison >= blessure.system.gravite) {
pointsGuerison -= blessure.system.gravite;
guerisonData.list.push(`1 Blessure ${blessure.system.label} (${blessure.system.gravite} points)`);
pointsGuerison -= blessure.system.gravite
guerisonData.list.push(`1 Blessure ${blessure.system.label} (${blessure.system.gravite} points)`)
ids.push(blessure.id)
}
}
if (ids.length > 0) {
await this.supprimerBlessures(it => ids.includes(it.id));
await this.supprimerBlessures(it => ids.includes(it.id))
}
if (blessures.length == ids.length) {
let pvManquants = this.system.sante.vie.max - this.system.sante.vie.value;
let pvSoignees = Math.min(pvManquants, Math.floor(pointsGuerison / 2));
pointsGuerison -= pvSoignees * 2;
guerisonData.list.push(pvSoignees + " Points de Vie soignés");
await this.santeIncDec('vie', +pvSoignees, false);
await this.santeIncDec('vie', +pvSoignees)
}
guerisonData.pointsConsommes = pointsGuerisonInitial - pointsGuerison;
return guerisonData;
@@ -2931,12 +2864,6 @@ export class RdDActor extends RdDBaseActorSang {
await this.diminuerQuantiteObjet(potion.id, 1, { supprimerSiZero: potion.supprimer });
}
/* -------------------------------------------- */
async onPreUpdateItem(item, change, options, id) {
if (item.isCompetencePersonnage() && item.system.defaut_carac && item.system.xp) {
await this.checkCompetenceXP(item.name, item.system.xp);
}
}
/* -------------------------------------------- */
async onCreateItem(item, options, id) {
switch (item.type) {

View File

@@ -26,7 +26,7 @@ import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, CATEGORIES_COMPETENCES_CREATURES } fr
import { RollDataAjustements } from "../rolldata-ajustements-v1.js";
import { MappingCreatureArme } from "../item/mapping-creature-arme.mjs";
import RollDialog from "../roll/roll-dialog.mjs";
import { ATTAQUE_ROLL_TYPES, DEFAULT_ROLL_TYPES, DIFF, ROLL_TYPE_ATTAQUE } from "../roll/roll-constants.mjs";
import { DEFAULT_ROLL_TYPES, DIFF, ROLL_TYPE_ATTAQUE } from "../roll/roll-constants.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2 } from "../settings/options-avancees.js";
import { PART_COMP } from "../roll/roll-part-comp.mjs";
import { RdDInitiative } from "../initiative.mjs";
@@ -56,8 +56,6 @@ export class RdDBaseActorReve extends RdDBaseActor {
getTaille() { return Misc.toInt(this.system.carac.taille?.value) }
getConstitution() { return this.getReve() }
getVie() { return this.getReve() }
getCaracVie() { return { [CARACS.VIE]: { label: "Vie", value: this.getVieMax(), type: "number" } } }
getForce() { return this.getReve() }
getAgilite() { return this.getForce() }
@@ -156,11 +154,11 @@ export class RdDBaseActorReve extends RdDBaseActor {
async computeArmure(dmg) { return this.getProtectionNaturelle() }
async remiseANeuf() { }
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { }
async ajoutExperience(rollData, hideChatMessage = 'show') { }
computeResumeBlessure() { }
computeResumeBlessure() { return []}
countBlessures(filter = it => !it.isContusion()) { return 0 }
async santeIncDec(name, inc, isCritique = false) { }
async santeIncDec(name, inc, isCritique) { }
async finDeRound(options = { terminer: false }) {
await this.finDeRoundSuppressionEffetsTermines(options)
@@ -257,15 +255,15 @@ export class RdDBaseActorReve extends RdDBaseActor {
if (competence) {
function getFieldPath(fieldName) {
switch (fieldName) {
case "niveau": return 'system.niveau';
case "dommages": return 'system.dommages';
case "carac_value": return 'system.carac_value';
case "niveau": return 'system.niveau'
case "dommages": return 'system.dommages'
case "carac_value": return 'system.carac_value'
}
return undefined
}
const path = getFieldPath(fieldName);
const path = getFieldPath(fieldName)
if (path) {
await competence.update({ [path]: value });
await competence.update({ [path]: value })
}
}
}
@@ -297,7 +295,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
/* -------------------------------------------- */
createCallbackExperience() {
return { action: r => this.appliquerAjoutExperience(r) }
return { action: r => this.ajoutExperience(r) }
}
/* -------------------------------------------- */
@@ -306,7 +304,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
return { action: r => this.appliquerAppelMoral(r) }
}
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { }
async ajoutExperience(rollData, hideChatMessage = 'show') { }
async appliquerAppelMoral(rollData) { }
async _onCloseRollDialog(html) { }
@@ -373,13 +371,11 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
RollDataAjustements.calcul(rollData, this);
await RdDResolutionTable.rollData(rollData);
this.gererExperience(rollData);
this.ajoutExperience(rollData);
await RdDResolutionTable.displayRollData(rollData, this)
return rollData.rolled;
}
gererExperience(rollData) { }
/* -------------------------------------------- */
async roll() {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
@@ -484,17 +480,15 @@ export class RdDBaseActorReve extends RdDBaseActor {
async rollCompetence(idOrName, options = { tryTarget: true, arme: undefined }) {
RdDEmpoignade.checkEmpoignadeEnCours(this)
const competence = this.getCompetence(idOrName);
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: { allowed: options.arme ? ATTAQUE_ROLL_TYPES : DEFAULT_ROLL_TYPES },
type: { allowed: DEFAULT_ROLL_TYPES },
selected: {
carac: competence.type == ITEM_TYPES.competencecreature ? { key: competence.name } : undefined,
comp: { key: competence.name },
diff: { type: options.arme ? DIFF.ATTAQUE : DIFF.LIBRE, value: competence.system.default_diffLibre ?? 0 },
attaque: options.arme ? { arme: { key: options.arme.id } } : undefined
diff: { type: DIFF.LIBRE, value: competence.system.default_diffLibre ?? 0 },
}
}
return await RollDialog.create(rollData)
@@ -566,7 +560,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
type: {
allowed: [ROLL_TYPE_ATTAQUE], current: ROLL_TYPE_ATTAQUE
}
};
}
return await RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose })
}
})
@@ -575,16 +569,18 @@ export class RdDBaseActorReve extends RdDBaseActor {
/** --------------------------------------------
* @param {*} arme item d'arme/compétence de créature
* @param {*} categorieArme catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession
* @param {*} maniement catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession
* @returns
*/
rollArme(arme, categorieArme = 'competence', token = undefined) {
async rollArme(arme, maniement = 'competence', token = undefined) {
token = token ?? RdDUtility.getSelectedToken(this)
const compToUse = RdDItemArme.getCompetenceArme(arme, categorieArme)
const compToUse = RdDItemArme.getCompetenceArme(arme, maniement)
if (!RdDItemArme.isUtilisable(arme)) {
ui.notifications.warn(`Arme inutilisable: ${arme.name} non équipée ou avec une résistance de 0 ou moins`)
return
}
if (!Targets.hasTargets()) {
RdDConfirm.confirmer({
settingConfirmer: "confirmer-combat-sans-cible",
@@ -596,7 +592,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
onAction: async () => {
this.rollCompetence(compToUse, { tryTarget: false, arme: arme })
}
});
})
return
}
@@ -606,11 +602,12 @@ export class RdDBaseActorReve extends RdDBaseActor {
return
}
const competence = this.getCompetence(compToUse)
if (competence.isCompetencePossession()) {
return RdDPossession.onAttaquePossession(target, this, competence);
const comp = this.getCompetence(compToUse)
if (comp.isCompetencePossession()) {
// TODO: vérifier si c'est possible, sinon simplifier
return RdDPossession.onAttaquePossession(target, this, comp);
}
RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme);
RdDCombat.rddCombatTarget(target, this, token).attaque(comp, arme, maniement)
})
}
@@ -657,28 +654,23 @@ export class RdDBaseActorReve extends RdDBaseActor {
jet => this.$onEncaissement(jet, show, attackerToken, defenderToken));
}
}
async $onEncaissement(jet, show, attackerToken, defenderToken) {
await this.onAppliquerJetEncaissement(jet, attackerToken);
await this.$afficherEncaissement(jet, show, defenderToken);
}
async onAppliquerJetEncaissement(encaissement, attackerToken) { }
async $afficherEncaissement(encaissement, show, defenderToken) {
async $onEncaissement(encaissement, show, attackerToken, defenderToken) {
await this.onAppliquerJetEncaissement(encaissement, attackerToken);
foundry.utils.mergeObject(encaissement, {
alias: defenderToken?.name ?? this.getAlias(),
hasPlayerOwner: this.hasPlayerOwner,
show: show ?? {}
}, { overwrite: false });
await ChatUtility.createChatWithRollMode(
await ChatMessage.create(ChatUtility.adaptVisibility(
{
roll: encaissement.roll,
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-encaissement.hbs', encaissement)
},
this
)
{ actor: this }))
if (!encaissement.hasPlayerOwner && encaissement.endurance != 0) {
encaissement = foundry.utils.duplicate(encaissement)
@@ -733,7 +725,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-accorder-cauchemar.hbs')
await this.appliquerAjoutExperience(rollData, true)
await this.ajoutExperience(rollData, true)
return rolled.isSuccess;
}

View File

@@ -8,6 +8,7 @@ import { RdDItemBlessure } from "../item/blessure.js";
import { ChatUtility } from "../chat-utility.js";
import { Misc } from "../misc.js";
import { RdDBaseActor } from "./base-actor.js";
import { CARACS } from "../rdd-carac.js";
/**
* Classe de base pour les acteurs qui peuvent subir des blessures
@@ -16,6 +17,14 @@ import { RdDBaseActor } from "./base-actor.js";
*/
export class RdDBaseActorSang extends RdDBaseActorReve {
async _preUpdate(changed, options, user) {
const updatedEndurance = changed?.system?.sante?.endurance
if (updatedEndurance && options.diff) {
await this.setEffect(STATUSES.StatusUnconscious, updatedEndurance.value == 0)
}
}
prepareActorData() {
this.system.sante.vie.max = Math.ceil((this.getTaille() + this.getConstitution()) / 2)
this.system.sante.vie.value = Math.min(this.system.sante.vie.value, this.system.sante.vie.max)
@@ -70,51 +79,64 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
return Math.min(0, Math.floor(this.getEncombrementMax() - this.encTotal));
}
countBlessures(filter) { return this.itemTypes[ITEM_TYPES.blessure].filter(filter).length }
isDead() { return this.system.sante.vie.value < -this.getSConst() }
nbBlessuresLegeres() { return this.itemTypes[ITEM_TYPES.blessure].filter(it => it.isLegere()).length }
nbBlessuresGraves() { return this.itemTypes[ITEM_TYPES.blessure].filter(it => it.isGrave()).length }
nbBlessuresCritiques() { return this.itemTypes[ITEM_TYPES.blessure].filter(it => it.isCritique()).length }
/* -------------------------------------------- */
computeResumeBlessure() {
const nbLegeres = this.nbBlessuresLegeres()
const nbGraves = this.nbBlessuresGraves()
const nbCritiques = this.nbBlessuresCritiques()
function descBlessure(count, name) {
return count > 0 ? [`${count} ${name}${count > 1 ? "s" : ""}`] : []
}
if (nbLegeres + nbGraves + nbCritiques == 0) {
return "Aucune blessure";
}
let resume = "Blessures:";
if (nbLegeres > 0) {
resume += " " + nbLegeres + " légère" + (nbLegeres > 1 ? "s" : "");
}
if (nbGraves > 0) {
if (nbLegeres > 0)
resume += ",";
resume += " " + nbGraves + " grave" + (nbGraves > 1 ? "s" : "");
}
if (nbCritiques > 0) {
if (nbGraves > 0 || nbLegeres > 0)
resume += ",";
resume += " une CRITIQUE !";
}
return resume;
const nbContusions = this.countBlessures(it => it.isContusion())
const nbLegeres = this.countBlessures(it => it.isLegere())
const nbGraves = this.countBlessures(it => it.isGrave())
const nbCritiques = this.countBlessures(it => it.isCritique())
return [
... (nbCritiques > 0 ? ['une CRITIQUE !'] : []),
...descBlessure(nbGraves, 'grave'),
...descBlessure(nbLegeres, 'légère'),
...descBlessure(nbContusions, 'contusion'),
]
}
blessuresASoigner() { return [] }
async computeArmure(attackerRoll) { return this.getProtectionNaturelle() }
async remiseANeuf() { }
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { }
async ajoutExperience(rollData, hideChatMessage = 'show') { }
/* -------------------------------------------- */
async onAppliquerJetEncaissement(encaissement, attackerToken) {
const santeOrig = foundry.utils.duplicate(this.system.sante);
const blessure = await this.ajouterBlessure(encaissement, attackerToken); // Will update the result table
const perteVie = await this.santeIncDec("vie", -encaissement.vie);
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance, blessure?.isCritique());
const blessure = this.nouvelleBlessure(encaissement.gravite, {
localisation: encaissement.dmg?.loc.label ?? '',
origine: attackerToken?.name ?? ''
})
if (blessure.system.gravite == encaissement.gravite) {
blessure.system.vie = encaissement.vie
blessure.system.endurance = encaissement.endurance
}
else { // aggravation du fait du nombre de blessures
blessure.system.vie = blessure.system.vie
const rollPerteEndurance = new Roll(blessure.system.endurance)
await rollPerteEndurance.evaluate()
blessure.system.endurance = rollPerteEndurance.total
}
const isCritique = blessure.system.gravite >= 6;
if (isCritique) {
blessure.system.endurance = this.getEnduranceActuelle()
}
// Will update the result table
if (blessure.system.gravite > 6) {
this.setEffect(STATUSES.StatusComma, true)
encaissement.mort = "à seconde blessure critique"
}
const perteVie = await this.santeIncDec("vie", -encaissement.vie)
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance, isCritique)
await this.createEmbeddedDocuments('Item', [blessure])
foundry.utils.mergeObject(encaissement, {
resteEndurance: perteEndurance.newValue,
@@ -123,7 +145,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
endurance: perteEndurance.perte,
vie: santeOrig.vie.value - perteVie.newValue,
blessure: blessure
});
})
}
/* -------------------------------------------- */
@@ -141,12 +163,13 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
let minValue = name == "vie" ? -this.getSConst() - 1 : 0;
result.newValue = Math.max(minValue, Math.min(compteur.value + inc, compteur.max));
//console.log("New value ", inc, minValue, result.newValue);
let fatigue = 0;
if (name == "endurance") {
if (result.newValue == 0 && inc < 0 && !isCritique) { // perte endurance et endurance devient 0 (sauf critique) -> -1 vie
sante.vie.value--;
result.perteVie = true;
if (result.newValue == 0 && inc < 0 && !isCritique) {
// perte endurance et endurance devient 0 (sauf critique) -> -1 vie
sante.vie.value--
result.perteVie = true
}
result.newValue = Math.max(0, result.newValue);
if (inc > 0) { // le max d'endurance s'applique seulement à la récupération
@@ -163,34 +186,39 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
if (ReglesOptionnelles.isUsing("appliquer-fatigue") && sante.fatigue && fatigue > 0) {
sante.fatigue.value = Math.max(sante.fatigue.value + fatigue, this.getFatigueMin());
}
await this.update({ "system.sante": sante }, { render: true })
await this.update({ "system.sante": sante })
if (perteEndurance > 1) {
// Peut-être sonné si 2 points d'endurance perdus d'un coup
foundry.utils.mergeObject(result, await this.jetEndurance(result.newValue));
} else if (name == "endurance" && inc > 0) {
await this.setSonne(false);
await this.setSonne(false)
}
if (this.isDead()) {
await this.setEffect(STATUSES.StatusComma, true);
await this.setEffect(STATUSES.StatusComma, true)
}
return result
}
async onRollTachePremiersSoins(blessureId, rollData, soigneurId) {
async callbackPremiersSoins(blessureId, rollData, soigneurId) {
await this.onRollTachePremiersSoins(blessureId,
rollData.v2 ? rollData.current.tache.tache : rollData.tache,
rollData.rolled.isETotal,
soigneurId)
}
async onRollTachePremiersSoins(blessureId, tache, isETotal, soigneurId) {
if (!this.isOwner) {
return RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
method: 'onRollTachePremiersSoins', args: [blessureId, rollData, soigneurId]
method: 'onRollTachePremiersSoins', args: [blessureId, tache, isETotal, soigneurId]
})
}
const blessure = this.getItem(blessureId, 'blessure')
if (blessure && !blessure.system.premierssoins.done) {
const tache = rollData.v2 ? rollData.current.tache.tache : rollData.tache
if (rollData.rolled.isETotal) {
if (isETotal) {
await blessure.update({
'system.difficulte': blessure.system.difficulte - 1,
'system.premierssoins.tache': Math.max(0, tache.system.points_de_tache_courant)
@@ -250,14 +278,6 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
return Math.max(0, Math.min(maxEndVie, maxEndGraves, maxEndCritiques));
}
async onUpdateActor(update, options, actorId) {
const updatedEndurance = update?.system?.sante?.endurance
if (updatedEndurance && options.diff) {
await this.setEffect(STATUSES.StatusUnconscious, updatedEndurance.value == 0)
}
await super.onUpdateActor(update, options, actorId)
}
async onCreateItem(item, options, id) {
await this.changeItemEffects(item)
await super.onCreateItem(item, options, id)
@@ -276,12 +296,12 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
async changeItemEffects(item) {
switch (item.type) {
case ITEM_TYPES.blessure:
await this.changeStateBleeding();
await this.changeStateBleeding()
break;
case ITEM_TYPES.maladie:
case ITEM_TYPES.poison:
await this.changeStateMalade();
break;
await this.changeStateMalade()
break
}
}
@@ -300,32 +320,15 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
}
/* -------------------------------------------- */
async ajouterBlessure(encaissement, attackerToken = undefined) {
if (encaissement.gravite < 0) return;
if (encaissement.gravite > 0) {
while (this.countBlessures(it => it.system.gravite == encaissement.gravite) >= RdDItemBlessure.maxBlessures(encaissement.gravite) && encaissement.gravite <= 6) {
nouvelleBlessure(gravite, options = { origine: undefined, localisation: '' }) {
if (gravite < 0) return
if (gravite > 0) {
while (this.countBlessures(it => it.system.gravite == gravite) >= RdDItemBlessure.maxBlessures(gravite) && gravite <= 6) {
// Aggravation
encaissement.gravite += 2
if (encaissement.gravite > 2) {
encaissement.vie += 2;
}
gravite += 2
}
}
const endActuelle = this.getEnduranceActuelle();
const blessure = await RdDItemBlessure.createBlessure(this, encaissement.gravite, encaissement.dmg?.loc.label ?? '', attackerToken);
if (blessure.isCritique()) {
encaissement.endurance = endActuelle
}
if (blessure.isMort()) {
this.setEffect(STATUSES.StatusComma, true);
encaissement.mort = true;
ChatMessage.create({
content: `<img class="chat-icon" src="icons/svg/skull.svg" data-tooltip="charge" />
<strong>${this.getAlias()} vient de succomber à une seconde blessure critique ! Que les Dragons gardent son Archétype en paix !</strong>`
});
}
return blessure;
return RdDItemBlessure.prepareBlessure(gravite, options);
}
async supprimerBlessure({ gravite }) {
@@ -337,8 +340,8 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
async supprimerBlessures(filterToDelete) {
const toDelete = this.filterItems(filterToDelete, ITEM_TYPES.blessure)
.map(it => it.id);
await this.deleteEmbeddedDocuments('Item', toDelete);
.map(it => it.id)
await this.deleteEmbeddedDocuments('Item', toDelete)
}
countBlessures(filter = it => !it.isContusion()) {
@@ -355,12 +358,11 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
return
}
const jetDeVie = await RdDDice.roll("1d20");
const sConst = this.getSConst();
const vie = this.system.sante.vie.value;
const isCritique = this.nbBlessuresCritiques() > 0;
const isGrave = this.nbBlessuresGraves();
const isEchecTotal = jetDeVie.total == 20;
const isCritique = this.countBlessures(it => it.isCritique()) > 0
const isGrave = this.countBlessures(it => it.isGrave())
const isEchecTotal = jetDeVie.total == 20
const isSuccess = jetDeVie.total == 1 || jetDeVie.total <= vie;
const perte = isSuccess ? 0 : 1 + (isEchecTotal ? vie + sConst : 0)
const prochainJet = (jetDeVie.total == 1 && vie > 0 ? 20 : 1) * (isCritique ? 1 : isGrave > 0 ? sConst : 0)
@@ -381,7 +383,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
ChatMessage.create({
content: msgText,
whisper: ChatUtility.getOwners(this)
});
})
}
/* -------------------------------------------- */
@@ -389,13 +391,14 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
const jetEndurance = (await RdDDice.roll("1d20")).total;
const sonne = jetEndurance == 20 || jetEndurance > (resteEndurance ?? this.system.sante.endurance.value)
if (sonne) {
await this.setSonne();
await this.setSonne(true)
}
return { jetEndurance, sonne }
}
async finDeRoundBlessures() {
const nbGraves = this.filterItems(it => it.isGrave(), 'blessure').length;
const nbGraves = this.itemTypes[ITEM_TYPES.blessure]
.filter(it => it.isGrave() && !it.system.premierssoins.done).length;
if (nbGraves > 0) {
// Gestion blessure graves : -1 pt endurance par blessure grave
await this.santeIncDec("endurance", -nbGraves);
@@ -404,8 +407,9 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
async setSonne(sonne = true) {
if (!game.combat && sonne) {
// TODO: vérifier si comportement toujours valable
ui.notifications.info(`${this.getAlias()} est hors combat, il ne reste donc pas sonné`);
return;
return
}
await this.setEffect(STATUSES.StatusStunned, sonne)
}

View File

@@ -49,11 +49,9 @@ export class RdDBaseActor extends Actor {
static init() {
Handlebars.registerHelper('actor-isFeminin', actor => actor.isFeminin())
Hooks.on("preUpdateItem", (item, change, options, id) => Misc.documentIfResponsible(item.parent)?.onPreUpdateItem(item, change, options, id))
Hooks.on("createItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onCreateItem(item, options, id))
Hooks.on("updateItem", (item, updates, options, id) => Misc.documentIfResponsible(item.parent)?.onUpdateItem(item, updates, options, id))
Hooks.on("deleteItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onDeleteItem(item, options, id))
Hooks.on("updateActor", (actor, change, options, actorId) => Misc.documentIfResponsible(actor)?.onUpdateActor(change, options, actorId))
}
static onSocketMessage(sockmsg) {
@@ -93,25 +91,11 @@ export class RdDBaseActor extends Actor {
}
static getRealActor(actorId, tokenId) {
if (tokenId) {
let token = canvas.tokens.get(tokenId)
if (token) {
return token.actor
}
}
return game.actors.get(actorId)
const actor = tokenId ? canvas.tokens.get(tokenId)?.actor : undefined
return actor ?? game.actors.get(actorId)
}
getAlias() {
if (this.token?.name != null && this.token != this.prototypeToken) {
return this.token.name
}
return this.name
}
isPersonnageJoueur() { return false }
static extractActorMin = (actor) => { return { id: actor?.id, type: actor?.type, name: actor?.name, img: actor?.img }; };
static extractActorMin(actor) { return { id: actor?.id, type: actor?.type, name: actor?.name, img: actor?.img } }
/**
* Cette methode surcharge Actor.create() pour ajouter si besoin des Items par défaut:
@@ -156,6 +140,15 @@ export class RdDBaseActor extends Actor {
super(docData, context);
}
getAlias() {
if (this.token?.name != null && this.token != this.prototypeToken) {
return this.token.name
}
return this.name
}
isPersonnageJoueur() { return false }
getCarac() {
return foundry.utils.duplicate(this.system.carac)
}
@@ -221,6 +214,41 @@ export class RdDBaseActor extends Actor {
}
}
async _preUpdate(changed, options, user) {
const updatedCarac = changed?.system?.carac
if (updatedCarac && (updatedCarac.force || updatedCarac.reve || updatedCarac.taille)) {
await this.setEffect(STATUSES.StatusSurEnc, this.isSurenc())
}
await this.delayedRenderSheet('_preUpdate', changed, options)
return super._preUpdate(changed, options, user)
}
_onUpdate(changed, options, userId) {
super._onUpdate(changed, options, userId)
if (userId == game.user.id){
this.delayedRenderSheet('_onUpdate', changed, options)
}
}
async delayedRenderSheet(caller, data, options) {
this.refreshDelayCounter = (this.refreshDelayCounter ?? 0)+1
if (this.refreshDelayCounter == 1) {
this.renderAfterDelay(this.refreshDelayCounter)
}
}
renderAfterDelay(currentCounter) {
setTimeout(async () => {
if (currentCounter == this.refreshDelayCounter) {
this.sheet?.render()
this.refreshDelayCounter = 0
}
else {
this.renderAfterDelay(this.refreshDelayCounter)
}
}, 30)
}
/* -------------------------------------------- */
prepareData() {
super.prepareData()
@@ -233,6 +261,7 @@ export class RdDBaseActor extends Actor {
prepareActorData() { }
async computeEtatGeneral() { }
/* -------------------------------------------- */
findPlayer() {
return game.users.players.find(player => player.active && player.character?.id == this.id);
@@ -285,14 +314,14 @@ export class RdDBaseActor extends Actor {
return this.getEffects().filter(it => it.statuses.has(effectId))
}
async setEffect(effectId, status) {
async setEffect(effectId, status, options = { render: true }) {
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 })
await this.deleteEmbeddedDocuments('ActiveEffect', effects.map(it => it.id), options)
}
if (status && effects.length == 0) {
await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(effectId)], { render: true })
await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(effectId)], options)
}
}
}
@@ -301,13 +330,13 @@ export class RdDBaseActor extends Actor {
this.removeEffects(it => it.id == id)
}
async removeEffects(filter = e => true) {
async removeEffects(filter = e => true, options = { render: true }) {
if (game.user.isGM) {
const ids = this.getEffects(filter)
.filter(it => this.canRemoveEffects(it))
.map(it => it.id)
if (ids.length > 0) {
await this.deleteEmbeddedDocuments('ActiveEffect', ids)
await this.deleteEmbeddedDocuments('ActiveEffect', ids, options)
}
}
@@ -326,16 +355,8 @@ export class RdDBaseActor extends Actor {
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) {
}
@@ -352,13 +373,13 @@ export class RdDBaseActor extends Actor {
}
async _removeItemFromConteneur(item) {
const updates = this.findConteneur(item)
.map(conteneur => {
const nouveauContenu = conteneur.system.contenu.filter(id => id != item.id)
return { _id: conteneur.id, 'system.contenu': nouveauContenu }
})
if (updates.length > 0) {
await this.updateEmbeddedDocuments('Item', updates)
const conteneur = this.findConteneur(item);
if (conteneur) {
const nouveauContenu = conteneur.system.contenu.filter(id => id != item.id)
const updates = { _id: conteneur.id, 'system.contenu': nouveauContenu }
if (updates.length > 0) {
await this.updateEmbeddedDocuments('Item', updates)
}
}
}
@@ -879,6 +900,7 @@ export class RdDBaseActor extends Actor {
ui.notifications.info(`${this.getAlias()} ne peut pas faire cette action: ${action}`)
}
ajoutExperience(rollData) { }
isAlcoolise() { return false }
async jetEthylisme() { this.actionImpossible("jet d'éthylisme") }
async rollAppelChance() { this.actionImpossible("appel à la chance") }

View File

@@ -15,8 +15,8 @@ export class RdDCreature extends RdDBaseActorSang {
}
async remiseANeuf() {
await this.removeEffects(e => true);
await this.supprimerBlessures(it => true);
await this.removeEffects(e => true)
await this.supprimerBlessures(it => true)
await this.update({
'system.sante.endurance.value': this.system.sante.endurance.max,
'system.sante.vie.value': this.system.sante.vie.max,

View File

@@ -18,6 +18,7 @@ export class RdDActorEntiteSheet extends RdDBaseActorReveSheet {
formData.niveau = this.actor.getNiveau()
delete formData.system.carac.niveau
formData.resonances = this.actor.system.sante.resonnance.actors.map(actorId => game.actors.get(actorId))
.filter(actor => actor != undefined)
.map(actor => { return { id: actor.id, name: actor.name, img: actor.img } })
return formData
}
@@ -75,6 +76,6 @@ export class RdDActorEntiteSheet extends RdDBaseActorReveSheet {
async resonanceDelete(actorId) {
console.log('Delete : ', actorId);
let newResonances = this.actor.system.sante.resonnance.actors.filter(id => id != actorId);
await this.actor.update({ 'system.sante.resonnance.actors': newResonances }, { renderSheet: false });
await this.actor.update({ 'system.sante.resonnance.actors': newResonances }, { render: false });
}
}

View File

@@ -43,9 +43,7 @@ export class RdDEntite extends RdDBaseActorReve {
async remiseANeuf() {
if (!this.isEntiteNonIncarnee()) {
await this.update({
'system.sante.endurance.value': this.system.sante.endurance.max
});
await this.update({ 'system.sante.endurance.value': this.system.sante.endurance.max })
}
await this.removeEffects(e => true)
}
@@ -85,12 +83,9 @@ export class RdDEntite extends RdDBaseActorReve {
if (this.isEntiteNonIncarnee()) {
return
}
encaissement.isEntiteIncarnee = true
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance);
foundry.utils.mergeObject(encaissement, {
resteEndurance: perteEndurance.newValue,
endurance: perteEndurance.perte,
blessure: RdDItemBlessure.prepareBlessure(encaissement.gravite, encaissement.dmg?.loc.label ?? '', attackerToken)
})
foundry.utils.mergeObject(encaissement, { resteEndurance: perteEndurance.newValue, endurance: perteEndurance.perte })
}
isEntiteAccordee(attacker) {

View File

@@ -46,9 +46,9 @@ export class RdDActorExportSheet extends RdDActorSheet {
formData.export = this.getMappingValues(formData.context, this.actor)
formData.competences = this.getCompetences(CATEGORIES_COMPETENCES_BASE)
formData.draconic = this.getCompetences(CATEGORIES_DRACONIC)
const legeres = this.actor.nbBlessuresLegeres()
const graves = this.actor.nbBlessuresGraves()
const critiques = this.actor.nbBlessuresCritiques()
const legeres = this.actor.countBlessures(it => it.isLegere())
const graves = this.actor.countBlessures(it => it.isGrave())
const critiques = this.actor.countBlessures(it => it.isCritique())
formData.etat = {
surenc: this.actor.computeMalusSurEncombrement(),
fatigue: {
@@ -103,11 +103,10 @@ export class RdDActorExportSheet extends RdDActorSheet {
gravite: this.html.find(event.currentTarget).data('gravite')
})
)
this.html.find('.click-blessure-add').click(async event =>
await this.actor.ajouterBlessure({
gravite: this.html.find(event.currentTarget).data('gravite')
})
)
this.html.find('.click-blessure-add').click(async event => {
const blessure = this.actor.nouvelleBlessure(this.html.find(event.currentTarget).data('gravite'))
await actor.createEmbeddedDocuments('Item', [blessure])
})
this.html.find('.button-export').click(async event => await
ExportScriptarium.INSTANCE.exportActors([this.actor],
`${this.actor.uuid}-${this.actor.name}`

View File

@@ -92,27 +92,28 @@ export class ChatUtility {
}
/* -------------------------------------------- */
static async createChatWithRollMode(messageData, actor = undefined, rollMode = game.settings.get("core", "rollMode")) {
switch (rollMode) {
static adaptVisibility( messageData, options = { actor: undefined, rollMode: undefined }) {
foundry.utils.mergeObject(options, { rollMode: game.settings.get("core", "rollMode") }, { overwrite: false });
switch (options.rollMode) {
case "blindroll": // GM only
if (!game.user.isGM) {
ChatUtility.blindMessageToGM(messageData)
messageData.whisper = [game.user];
messageData.content = "Message envoyé en aveugle au Gardien"
messageData.whisper = [game.user]
messageData.content = "Message envoyé en aveugle au Gardien";
}
else {
messageData.whisper = ChatUtility.getGMs()
}
break
break;
case "gmroll":
messageData.whisper = actor ? ChatUtility.getOwners(actor) : ChatUtility.getUserAndGMs()
break
messageData.whisper = options.actor ? ChatUtility.getOwners(options.actor) : ChatUtility.getUserAndGMs()
break;
case "selfroll":
messageData.whisper = [game.user]
break
}
messageData.alias = messageData.alias ?? actor?.name ?? game.user.name
return await ChatMessage.create(messageData)
messageData.alias = messageData.alias ?? options.actor?.name ?? game.user.name
return messageData
}
static tellToUser(message) {
@@ -134,6 +135,7 @@ export class ChatUtility {
whisper: ChatUtility.getUserAndGMs()
})
}
static getOwners(document) {
return document ? game.users.filter(it => document.getUserLevel(it) == CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) : [game.user]
}
@@ -216,7 +218,7 @@ export class ChatUtility {
static async onRenderChatMessage(chatMessage, html, data) {
const rddTimestamp = chatMessage.getFlag(SYSTEM_RDD, 'rdd-timestamp')
const heureRdD = $(html).find('header.message-header .heure-rdd')
if (rddTimestamp && heureRdD.length==0) {
if (rddTimestamp && heureRdD.length == 0) {
const messageTimestamp = $(html).find('header.message-header .message-timestamp');
const timestamp = new RdDTimestamp(rddTimestamp);
const timestampData = timestamp.toCalendrier();

View File

@@ -48,7 +48,7 @@ export class Distance {
static isVisible(token, defenderToken) {
// TODO: regarder les StatusEffect aveuglé?
if (Distance.$isToken(token) && Distance.$isToken(defenderToken)) {
return canvas.effects.visibility.testVisibility(defenderToken.getCenterPoint(), { object: token })
return canvas.visibility.testVisibility(defenderToken.getCenterPoint(), { object: token })
}
return true
}

View File

@@ -0,0 +1,19 @@
export class RdDActiveEffect extends ActiveEffect {
async _preCreate(data, options, user) {
await this.parent?.delayedRenderSheet('_preCreateEffect', data, options)
return super._preCreate(data, options, user)
}
async _preUpdate(changed, options, user) {
await this.parent?.delayedRenderSheet('_preUpdateEffect', changed, options)
return super._preUpdate(changed, options, user)
}
async _preDelete(options, user) {
await this.parent?.delayedRenderSheet('_preDeleteEffect', { id: this.id }, options)
return super._preDelete(options, user)
}
}

View File

@@ -1,4 +1,4 @@
import { ChatUtility } from "./chat-utility.js";
import { Grammar } from "./grammar.js";
import { RdDInitiative } from "./initiative.mjs";
import { RdDItem } from "./item.js";
@@ -71,6 +71,36 @@ export class RdDItemCompetence extends RdDItem {
}
return undefined
}
async _preUpdate(changed, options, user) {
await this.checkCompetenceXP(changed.system?.xp)
return super._preUpdate(changed, options, user)
}
async checkCompetenceXP(newXP, display = true) {
if (this.actor?.isPersonnage() && newXP && newXP != this.system.xp && newXP > 0) {
const newNiv = this.system.niveau + 1
let needed = RdDItemCompetence.getCompetenceNextXp(newNiv)
if (newXP >= needed) {
const xpData = {
alias: this.actor.getAlias(),
competence: this.name,
niveau: newNiv,
xp: newXP,
archetype: this.system.niveau_archetype,
archetypeWarning: newNiv > this.system.niveau_archetype
}
if (display) {
ChatMessage.create({
whisper: ChatUtility.getOwners(this.actor),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-competence-xp.hbs`, xpData)
})
}
return xpData
}
}
}
/* -------------------------------------------- */
static getLabelCategorie(category) {
return CATEGORIES_COMPETENCES[category].label;
@@ -136,7 +166,7 @@ export class RdDItemCompetence extends RdDItem {
return troncList;
}
}
return [];
return []
}
/* -------------------------------------------- */

View File

@@ -41,6 +41,11 @@ export class RdDItemSort extends RdDItem {
return value ? value.replace('variable', 'var') : ''
}
static computeTotalXP(sorts) {
return sorts.map(sort => RdDItemSort.isDifficulteVariable(sort) ? 70 : -10 * Misc.toInt(sort.system.difficulte))
.reduce(Misc.sum(), 0)
}
static isSortOnCoord(sort, coord) {
let tmr = TMRUtility.getTMR(coord)
const caseTMR = sort.system.caseTMR.toLowerCase();

View File

@@ -85,6 +85,10 @@ export const defaultItemImg = {
munition: "systems/foundryvtt-reve-de-dragon/icons/objets/fleche.webp"
}
const ITEM_TYPES_PLURIEL = {
[ITEM_TYPES.jeu]: 'jeux'
}
/* -------------------------------------------- */
export class RdDItem extends Item {
@@ -112,6 +116,13 @@ export class RdDItem extends Item {
return true;
}
static itemTypePluriel(type) {
if (ITEM_TYPES[type]) {
return ITEM_TYPES_PLURIEL[type] ?? (type + 's')
}
console.error(`Item type ${type} is undefined`)
return type
}
static async getCorrespondingItem(itemRef) {
if (itemRef.pack) {
return await SystemCompendiums.loadDocument(itemRef)
@@ -163,6 +174,21 @@ export class RdDItem extends Item {
super(docData, context);
}
async _preCreate(data, options, user) {
await this.parent?.delayedRenderSheet('_preCreateItem', data, options)
return super._preCreate(data, options, user)
}
async _preUpdate(changed, options, user) {
await this.parent?.delayedRenderSheet('_preUpdateItem', changed, options)
return super._preUpdate(changed, options, user)
}
async _preDelete(options, user) {
await this.parent?.delayedRenderSheet('_preDeleteItem', { id: this.id }, options)
return super._preDelete(options, user)
}
getUniteQuantite() {
switch (this.type) {
case ITEM_TYPES.monnaie: return "(Pièces)"

View File

@@ -19,7 +19,7 @@ const definitionsBlessures = [
{ type: "legere", gravite: 2, endurance: "1d6", vie: 0, label: 'Légère', max: 5, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
{ type: "grave", gravite: 4, endurance: "2d6", vie: -2, label: 'Grave', max: 2, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
{ type: "critique", gravite: 6, endurance: "-100", vie: -4, label: 'Critique', max: 1, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
{ type: "mort", gravite: 8, label: 'Mort', max: 1, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/mort.webp" }
{ type: "mort", gravite: 8, endurance: "-100", vie: 0, label: 'Mort', max: 1, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/mort.webp" }
]
export class RdDItemBlessure extends RdDItem {
@@ -71,13 +71,13 @@ export class RdDItemBlessure extends RdDItem {
return 0
}
static async createBlessure(actor, gravite, localisation = '', attackerToken = undefined) {
const blessure = RdDItemBlessure.prepareBlessure(gravite, localisation, attackerToken);
const blessures = await actor.createEmbeddedDocuments('Item', [blessure])
static async createBlessure(actor, gravite, options = { localisation: '', origine: '', render: true }) {
const blessure = RdDItemBlessure.prepareBlessure(gravite, options);
const blessures = await actor.createEmbeddedDocuments('Item', [blessure], options)
return blessures[0]
}
static prepareBlessure(gravite, localisation, attackerToken) {
static prepareBlessure(gravite, options = { localisation: '', origine: '' }) {
const definition = RdDItemBlessure.getDefinition(gravite);
return {
name: definition.label,
@@ -85,9 +85,11 @@ export class RdDItemBlessure extends RdDItem {
img: definition.icon,
system: {
gravite: gravite,
vie: definition.vie,
endurance: definition.endurance,
difficulte: -gravite,
localisation: localisation,
origine: attackerToken?.name ?? ""
localisation: options.localisation,
origine: options.origine
}
}
}
@@ -104,11 +106,9 @@ export class RdDItemBlessure extends RdDItem {
async updateTacheSoinBlessure(tache) {
if (tache) {
await tache.update({
system: {
itemId: this.id,
difficulte: Math.min(this.system.difficulte, tache.system.difficulte),
points_de_tache_courant: Math.max(0, this.system.premierssoins.tache)
}
'system.itemId': this.id,
'system.difficulte': Math.min(this.system.difficulte, tache.system.difficulte),
'system.points_de_tache_courant': Math.max(0, this.system.premierssoins.tache)
});
}
}
@@ -160,7 +160,7 @@ export class RdDItemBlessure extends RdDItem {
message.content += ` -- une blessure ${label} reste stable`;
}
}
await this.update(update);
await this.update(update)
}
}

View File

@@ -28,6 +28,7 @@ const _MONTRER = {
}
const _SPLIT = {
code: 'item-split', label: 'Séparer le goupe', icon: 'fa-solid fa-unlink',
actorFilter: actor => actor.isOwner,
filter: it => Misc.toInt(it.system.quantite) > 1 && it.parent?.type != ACTOR_TYPES.commerce,
action: (item, actor) => RdDSheetUtility.splitItem(item, actor)
}
@@ -45,6 +46,7 @@ const _DELETE = {
}
const _EQUIPER = {
code: 'item-equip', label: 'Equiper', icon: it => it.system.equipe ? 'fa-solid fa-hand-rock' : 'fa-regular fa-hand-paper',
actorFilter: actor => actor.isPersonnage(),
filter: it => !it.estContenu && it.isEquipable(),
action: (item, actor) => actor.equiperObjet(item)
}
@@ -52,26 +54,31 @@ const _EQUIPER = {
const _CUISINER = {
code: 'item-cuisiner', label: 'Cuisiner',
img: 'systems/foundryvtt-reve-de-dragon/assets/actions/cuisine.svg',
actorFilter: actor => actor.isPersonnage(),
filter: it => it.getUtilisation() == 'cuisine' && it.system.sust > 0,
action: (item, actor) => actor.preparerNourriture(item)
}
const _MANGER_CRU = {
code: 'item-manger-cru', label: 'Manger cru', icon: 'fa-solid fa-drumstick-bite',
actorFilter: actor => actor.isPersonnage(),
filter: it => it.getUtilisation() == 'cuisine' && it.system.sust > 0,
action: (item, actor) => actor.mangerNourriture(item)
}
const _MANGER = {
code: 'item-manger', label: 'Manger', icon: 'fa-solid fa-utensils',
actorFilter: actor => actor.isPersonnage(),
filter: it => !(it.system.boisson),
action: (item, actor) => actor.mangerNourriture(item)
}
const _BOIRE = {
code: 'item-boire', label: 'Boire', icon: 'fa-solid fa-glass-water',
actorFilter: actor => actor.isPersonnage(),
filter: it => it.system.boisson,
action: (item, actor) => actor.mangerNourriture(item)
}
const _DECOCTION = {
code: 'item-decoction', label: 'Décoction', icon: 'fa-solid fa-flask-vial',
actorFilter: actor => actor.isPersonnage(),
action: (item, actor) => actor.fabriquerDecoctionHerbe(item)
}
@@ -82,17 +89,20 @@ const _OUVRIR = {
}
const _LIRE = {
code: 'item-lire', label: 'Lire', icon: 'fa-solid fa-book-open',
actorFilter: actor => actor.isPersonnage(),
action: (item, actor) => actor.actionLire(item)
}
const _REFOULER = {
code: 'item-refouler', label: 'Refouler', icon: 'fa-solid fa-burst',
actorFilter: actor => actor.isPersonnage(),
filter: it => it.system.refoulement > 0,
action: (item, actor) => actor.actionRefoulement(item)
}
const _SORT_RESERVE = {
code: 'item-sortreserve-add', label: 'Ajouter en réserve', icon: 'fa-solid fa-sparkles',
actorFilter: actor => actor.isPersonnage(),
filter: it => game.user.isGM && !it.system.isrituel,
action: (item, actor) => actor.addSortReserve(item)
}
@@ -118,6 +128,7 @@ export class ItemAction {
static applies(action, item, options) {
return action && item
&& item.isActionAllowed(action.code)
&& (!action.actorFilter || (item.actor && action.actorFilter(item.actor)))
&& (!action.filter || action.filter(item))
&& (action.allowLimited || options.editable)
&& (!action.optionsFilter || action.optionsFilter(options))

View File

@@ -77,41 +77,41 @@ export class RdDInventaireItemSheet extends RdDItemSheetV1 {
}
async onAddMilieu(event) {
const milieu = this.html.find('input.input-selection-milieu').val();
const milieu = this.html.find('input.input-selection-milieu').val()
if (!milieu) {
ui.notifications.warn(`Choisissez le milieu dans lequel se trouve le/la ${this.item.name}`);
ui.notifications.warn(`Choisissez le milieu dans lequel se trouve le/la ${this.item.name}`)
return
}
const list = this.item.getEnvironnements();
const exists = list.find(it => it.milieu == milieu);
const list = this.item.getEnvironnements()
const exists = list.find(it => it.milieu == milieu)
if (exists) {
ui.notifications.warn(`${this.item.name} a déjà une rareté ${exists.rarete} en ${milieu} (fréquence: ${exists.frequence})`);
return
}
const rarete = RdDRaretes.rareteFrequente();
const added = { milieu, rarete: rarete.code, frequence: rarete.frequence };
const rarete = RdDRaretes.rareteFrequente()
const added = { milieu, rarete: rarete.code, frequence: rarete.frequence }
const newList = [added, ...list].sort(Misc.ascending(it => it.milieu))
await this.item.update({ 'system.environnement': newList })
}
async onDeleteMilieu(event) {
const milieu = this.$getEventMilieu(event);
const milieu = this.$getEventMilieu(event)
if (milieu != undefined) {
const newList = this.item.getEnvironnements().filter(it => it.milieu != milieu)
.sort(Misc.ascending(it => it.milieu));
await this.item.update({ 'system.environnement': newList });
.sort(Misc.ascending(it => it.milieu))
await this.item.update({ 'system.environnement': newList })
}
}
async onChange(event, doMutation) {
const list = this.item.system.environnement;
const milieu = this.$getEventMilieu(event);
const updated = list.find(it => it.milieu == milieu);
const list = this.item.system.environnement
const milieu = this.$getEventMilieu(event)
const updated = list.find(it => it.milieu == milieu)
if (updated) {
doMutation(updated);
doMutation(updated)
const newList = [...list.filter(it => it.milieu != milieu), updated]
.sort(Misc.ascending(it => it.milieu));
await this.item.update({ 'system.environnement': newList });
.sort(Misc.ascending(it => it.milieu))
await this.item.update({ 'system.environnement': newList })
}
}

View File

@@ -20,7 +20,7 @@ export class RdDFauneItemSheet extends RdDInventaireItemSheet {
'system.actor.pack': linkedActor.pack,
'system.actor.id': linkedActor._id,
'system.actor.name': linkedActor.name
});
})
}
else {
ui.notifications.warn(`${linkedActor.name} ne provient pas d'un compendium.
@@ -32,7 +32,7 @@ export class RdDFauneItemSheet extends RdDInventaireItemSheet {
'system.actor.pack': '',
'system.actor.id': '',
'system.actor.name': ''
});
})
}
}

View File

@@ -16,22 +16,18 @@ class Migration {
async migrate() { }
async applyItemsUpdates(computeUpdates) {
await game.actors.forEach(async (actor) => {
await Promise.all(game.actors.map(actor => {
const actorItemUpdates = computeUpdates(actor.items).filter(it => it != undefined);
if (actorItemUpdates.length > 0) {
console.log(
this.code,
`Applying updates on actor ${actor.name} items`,
actorItemUpdates
);
await actor.updateEmbeddedDocuments("Item", actorItemUpdates);
console.log(this.code, `Applying updates on actor ${actor.name} items`, actorItemUpdates);
return actor.updateEmbeddedDocuments("Item", actorItemUpdates);
}
});
}))
const itemUpdates = computeUpdates(game.items).filter(it => it != undefined);
const itemUpdates = computeUpdates(game.items).filter(it => it != undefined)
if (itemUpdates.length > 0) {
console.log(this.code, "Applying updates on items", itemUpdates);
await Item.updateDocuments(itemUpdates);
console.log(this.code, "Applying updates on items", itemUpdates)
await Item.updateDocuments(itemUpdates)
}
}
}
@@ -58,13 +54,13 @@ class _1_5_34_migrationPngWebp {
//Migrate system png to webp
await Item.updateDocuments(itemsUpdates);
await Actor.updateDocuments(actorsUpdates);
game.actors.forEach(actor => {
if (actor.token?.img && actor.token.img.match(regexOldPngJpg)) {
actor.update({ "token.img": convertImgToWebp(actor.token.img) });
}
const actorItemsToUpdate = prepareDocumentsImgUpdate(actor.items);
actor.updateEmbeddedDocuments('Item', actorItemsToUpdate);
});
await Promise.all(game.actors
.filter(actor => actor.token?.img && actor.token.img.match(regexOldPngJpg))
.map(actor => actor.update({ "token.img": convertImgToWebp(actor.token.img) }))
)
await Promise.all(game.actors.map(actor =>
actor.updateEmbeddedDocuments('Item', prepareDocumentsImgUpdate(actor.items))
))
}
}
@@ -125,16 +121,15 @@ class _10_0_21_VehiculeStructureResistanceMax extends Migration {
get version() { return "10.0.21"; }
async migrate() {
await game.actors
.filter((actor) => actor.type == "vehicule")
.forEach(async (actor) => {
await actor.update({
await Promise.all(
game.actors.filter(actor => actor.type == "vehicule")
.map(actor => actor.update({
'system.etat.resistance.value': actor.system.resistance,
'system.etat.resistance.max': actor.system.resistance,
'system.etat.structure.value': actor.system.structure,
'system.etat.structure.max': actor.system.structure
})
});
}))
)
}
}
@@ -192,9 +187,9 @@ class _10_2_5_ArmesTirLancer extends Migration {
get version() { return "10.2.5"; }
migrateArmeTirLancer(it) {
let updates = foundry.utils.mergeObject({ _id: it.id }, this.getMapping(it).updates);
console.log(it.name, updates);
return updates;
const updates = foundry.utils.mergeObject({ _id: it.id }, this.getMapping(it).updates)
console.log(it.name, updates)
return updates
}
async migrate() {

View File

@@ -24,6 +24,13 @@ export class Misc {
return text.charAt(0).toLowerCase() + text.slice(1);
}
static stripHtml(html)
{
const tmp = document.createElement("DIV")
tmp.innerHTML = html
return tmp.textContent || tmp.innerText || ""
}
static toSignedString(number) {
const value = parseInt(number)
const isPositiveNumber = value != NaN && value > 0;

View File

@@ -168,10 +168,18 @@ export class RdDCarac {
const total = Object.values(carac ?? {}).filter(c => !c.derivee)
.map(it => parseInt(it.value))
.reduce(Misc.sum(), 0);
const beauteSuperieur10 = Math.max((beaute ?? 10) - 10, 0);
const beauteSuperieur10 = Math.max((beaute ?? 10) - 10, 0)
return total + beauteSuperieur10;
}
static computeTotalXp(carac, beaute = undefined) {
const totalXp = Object.values(carac ?? {}).filter(c => !c.derivee)
.map(it => RdDCarac.getCaracXp(0, Misc.toInt(it.value)) + Misc.toInt(it.xp))
.reduce(Misc.sum(), 0);
const beauteXp = beaute > 10 ? RdDCarac.getCaracXp(10, beaute) : 0
return totalXp + beauteXp;
}
static levelUp(it) {
it.xpNext = RdDCarac.getCaracNextXp(it.value);
it.isLevelUp = (it.xp >= it.xpNext);
@@ -184,12 +192,16 @@ export class RdDCarac {
/* -------------------------------------------- */
static getCaracNextXp(value) {
const nextValue = Number(value) + 1;
value = Number(value);
const nextValue = value + 1;
// xp est le coût pour atteindre cette valeur, on regarde donc le coût de la valeur+1
return RdDCarac.getCaracXp(nextValue);
return RdDCarac.getCaracXp(value, nextValue)
}
static getCaracXp(targetValue) {
return RdDCarac.getCaracDerivee(targetValue)?.xp ?? 200;
static getCaracXp(from, to) {
return Array.from({ length: to - from },
(_, i) => from + i + 1)
.map(it => RdDCarac.getCaracDerivee(it)?.xp ?? 200)
.reduce(Misc.sum(), 0)
}
}

View File

@@ -63,6 +63,7 @@ export class RdDCombatManager extends Combat {
it.token.id == tokenId
)
}
static getRangInitiativeCombatant(actorId, tokenId) {
const combatant = RdDCombatManager.getCombatant(actorId, tokenId)
return combatant?.system.init?.rang
@@ -387,7 +388,7 @@ export class RdDCombat {
/* -------------------------------------------- */
static onMsgEncaisser(msg) {
let defender = canvas.tokens.get(msg.defenderToken.id).actor;
let defender = canvas.tokens.get(msg.defenderToken.id)?.actor;
if (Misc.isOwnerPlayer(defender)) {
let attackerRoll = msg.attackerRoll;
let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : undefined;
@@ -466,24 +467,10 @@ export class RdDCombat {
this.defenderId = this.defender.id
this.attackerTokenId = attackerTokenId
this.defenderTokenId = defenderTokenId
this.attackerToken = RdDCombat.$extractAttackerTokenData(attacker, attackerTokenId)
this.defenderToken = RdDCombat.$extractDefenderTokenData(defender, defenderTokenId, target)
this.attackerToken = Targets.getTokenData(attacker, attackerTokenId)
this.defenderToken = Targets.getTokenData(defender, defenderTokenId, target)
}
static $extractAttackerTokenData(attacker, attackerTokenId) {
const token = canvas.tokens.get(attackerTokenId);
return token ? Targets.extractTokenData(token) : Targets.buildActorTokenData(attackerTokenId, attacker)
}
static $extractDefenderTokenData(defender, defenderTokenId, target) {
if (target) {
return Targets.extractTokenData(target)
}
const token = canvas.tokens.get(defenderTokenId);
return token ? Targets.extractTokenData(token) : Targets.buildActorTokenData(defenderTokenId, defender)
}
/* -------------------------------------------- */
async onEvent(button, event) {
const chatMessage = ChatUtility.getChatMessage(event);
@@ -518,8 +505,8 @@ export class RdDCombat {
/* -------------------------------------------- */
attaqueChanceuse(attackerRoll) {
ui.notifications.info("L'attaque est rejouée grâce à la chance")
attackerRoll.essais.attaqueChance = true;
this.attaque(attackerRoll, attackerRoll.arme);
attackerRoll.essais.attaqueChance = true
this.attaque(attackerRoll, attackerRoll.arme)
}
/* -------------------------------------------- */
@@ -646,11 +633,11 @@ export class RdDCombat {
}
}
async attaqueV2() {
async attaqueV2(options = undefined) {
if (!await this.attacker.accorder(this.defender, 'avant-attaque')) {
return
}
await this.doRollAttaque({
const rollData = {
ids: {
actorId: this.attackerId,
actorTokenId: this.attackerTokenId,
@@ -658,8 +645,19 @@ export class RdDCombat {
opponentTokenId: this.defenderTokenId,
},
type: { allowed: ['attaque'], current: 'attaque' },
selected: {},
passeArme: foundry.utils.randomID(16),
})
}
if (options) {
rollData.selected = {
attaque: {
comp: { id: options.comp.id },
arme: { id: options.arme.id },
main: options.main
}
}
}
await this.doRollAttaque(rollData)
}
async doRollAttaque(rollData, callbacks = []) {
@@ -725,7 +723,7 @@ export class RdDCombat {
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)),
speaker: ChatMessage.getSpeaker({ actor: this.defender, token: canvas.tokens.get(this.defenderTokenId) }),
alias: this.attacker?.getAlias(),
whisper: ChatUtility.getOwners(this.defender),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.hbs', defenseData)
@@ -740,12 +738,14 @@ export class RdDCombat {
}
/* -------------------------------------------- */
async attaque(competence, arme) {
async attaque(competence, arme, main) {
if (!await this.attacker.accorder(this.defender, 'avant-attaque')) {
return
}
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
return this.attacker.rollCompetence(competence.name, { arme: arme })
return this.attaqueV2(
{ comp: competence, arme: arme, main: main }
)
}
if (arme.system.cac == EMPOIGNADE) {
RdDEmpoignade.onAttaqueEmpoignade(this.attacker, this.defender)
@@ -754,7 +754,7 @@ export class RdDCombat {
RdDEmpoignade.checkEmpoignadeEnCours(this.attacker)
let rollData = this._prepareAttaque(competence, arme)
console.log("RdDCombat.attaque >>>", rollData);
console.log("RdDCombat.attaque >>>", rollData)
if (arme) {
this.attacker.verifierForceMin(arme);
}
@@ -929,7 +929,7 @@ export class RdDCombat {
async _chatMessageDefense(paramDemandeDefense, defenderRoll) {
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)),
speaker: ChatMessage.getSpeaker({ actor: this.defender, token: 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-v1.hbs', paramDemandeDefense),
@@ -996,9 +996,9 @@ export class RdDCombat {
const arme = rollData.arme;
const avecArme = !['', 'sans-armes', 'armes-naturelles'].includes(arme?.system.categorie_parade ?? '');
const action = (rollData.attackerRoll ? (arme ? "la parade" : "l'esquive") : "l'attaque");
ChatUtility.createChatWithRollMode(
await ChatMessage.create(ChatUtility.adaptVisibility(
{ content: `<strong>Maladresse à ${action}!</strong> ` + await RdDRollTables.getMaladresse({ arme: avecArme }) },
this.defender)
{ actor: this.defender }))
}
/* -------------------------------------------- */
@@ -1122,9 +1122,9 @@ export class RdDCombat {
async infoAttaquantDesarme(rollData) {
if (/*TODO: parade?*/!rollData.attackerRoll?.particuliere) {
// TODO: attaquant doit jouer résistance et peut être désarmé p132
ChatUtility.createChatWithRollMode(
await ChatMessage.create(ChatUtility.adaptVisibility(
{ content: `(à gérer) L'attaquant doit jouer résistance et peut être désarmé (p132)` },
this.defender)
{ actor: this.defender }))
}
}
@@ -1156,9 +1156,9 @@ export class RdDCombat {
console.log("RdDCombat._onParadeParticuliere >>>", defenderRoll);
if (!defenderRoll.attackerRoll.isPart) {
// TODO: attaquant doit jouer résistance et peut être désarmé p132
ChatUtility.createChatWithRollMode(
await ChatMessage.create(ChatUtility.adaptVisibility(
{ content: `(à gérer) L'attaquant doit jouer résistance et peut être désarmé (p132)` },
this.defender)
{ actor: this.defender }))
}
}
/* -------------------------------------------- */
@@ -1243,9 +1243,9 @@ export class RdDCombat {
/* -------------------------------------------- */
async _onEsquiveParticuliere(defenderRoll) {
console.log("RdDCombat._onEsquiveParticuliere >>>", defenderRoll);
ChatUtility.createChatWithRollMode(
await ChatMessage.create(ChatUtility.adaptVisibility(
{ content: "<strong>Vous pouvez esquiver une deuxième fois!</strong>" },
this.defender);
{ actor: this.defender }))
}
/* -------------------------------------------- */

View File

@@ -27,20 +27,8 @@ const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/;
export class RdDCommands {
static init() {
const rddCommands = new RdDCommands();
game.system.rdd.commands = rddCommands;
Hooks.on("chatMessage", (html, content, msg) => {
if (content[0] == '/') {
let regExp = /(\S+)/g;
let commands = content.match(regExp);
if (rddCommands.processChatCommand(commands, content, msg)) {
return false;
}
}
return true;
});
game.system.rdd.commands = new RdDCommands()
Hooks.on("chatMessage", (chatLog, message, msg) => game.system.rdd.commands.onChatMessage(message, msg))
}
constructor() {
@@ -116,6 +104,7 @@ export class RdDCommands {
this.registerCommand({
path: ["/xp", "carac"], func: (content, msg, params) => this.getCoutXpCarac(msg, params),
descr: `Détermine le coût d'expérience pour augmenter une caractéristique. Exemples:
<br>/xp carac 12 15: coût pour passer de 12 15
<br>/xp carac 15: coût pour atteindre 15 (depuis 14)`
});
@@ -215,6 +204,17 @@ export class RdDCommands {
}
onChatMessage(message, msg = {}) {
const content = Misc.stripHtml(message)
if (content[0] == '/') {
const commands = content.match(/(\S+)/g)
if (this.processChatCommand(commands, content, msg)) {
return false
}
}
return true
}
/* -------------------------------------------- */
/* Manage chat commands */
processChatCommand(commandLine, content = '', msg = {}) {
@@ -440,13 +440,18 @@ export class RdDCommands {
/* -------------------------------------------- */
getCoutXpCarac(msg, params) {
if (params && params.length == 1) {
let to = Number(params[0]);
return RdDCommands._chatAnswer(msg, `Coût pour passer une caractéristique de ${to - 1} à ${to}: ${RdDCarac.getCaracXp(to)}`);
}
else {
return false;
if (params) {
if (params.length == 1) {
const to = Number(params[0])
return RdDCommands._chatAnswer(msg, `Coût pour passer une caractéristique de ${to - 1} à ${to}: ${RdDCarac.getCaracXp(to - 1, to)}`);
}
if (params.length == 2) {
const from = Number(params[0]);
const to = Number(params[1]);
return RdDCommands._chatAnswer(msg, `Coût pour passer une caractéristique de ${from} à ${to}: ${RdDCarac.getCaracXp(from, to)}`);
}
}
return false
}
async creerSignesDraconiques() {

View File

@@ -15,21 +15,28 @@ export class RdDEmpoignade {
}
/* -------------------------------------------- */
static getActorEmpoignade(actorId) {
const actor = game.actors.get(actorId)
if (actor == undefined) {
ui.notifications.warn(`Impossible de retrouver l'acteur ${actorId}, l'empoignade ne peut pas être continuée.`)
}
return actor
}
static isCombatantEmpoignade(actorId, tokenId) {
const combatant = RdDCombatManager.getCombatant(actorId, tokenId)
return MAP_PHASE.empoignade.rang == combatant?.system.init?.rang
return combatant && MAP_PHASE.empoignade.rang == combatant?.system.init?.rang
}
static async ajustementEmpoignade(attacker, defender, adjust = 1) {
let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
if (empoignade?.system.empoigneurid == defender.id) {
let empoignade = RdDEmpoignade.getEmpoignade(defender, attacker)
empoignade = RdDEmpoignade.getEmpoignade(defender, attacker)
return await RdDEmpoignade.$ajustementEmpoignade(empoignade, defender, attacker, - adjust);
}
return await RdDEmpoignade.$ajustementEmpoignade(empoignade, attacker, defender, adjust);
}
static async $ajustementEmpoignade(empoignade, attacker, defender, adjust) {
const empId = empoignade?.system.empoignadeid ?? foundry.utils.randomID(16);
const empFin = (empoignade?.system.pointsemp ?? 0) + adjust
@@ -73,30 +80,32 @@ export class RdDEmpoignade {
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
let defenseMode = event.currentTarget.attributes['data-defense-mode'].value
RdDEmpoignade.onDefenseEmpoignade(rollData, defenseMode, "Corps à corps", "melee")
});
})
$(html).on("click", '.defense-empoignade-esquive', event => {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
let defenseMode = event.currentTarget.attributes['data-defense-mode'].value
RdDEmpoignade.onDefenseEmpoignade(rollData, defenseMode, "Esquive", "derobee")
});
})
$(html).on("click", '.empoignade-poursuivre', event => {
let attackerId = event.currentTarget.attributes['data-attackerId'].value
let defenderId = event.currentTarget.attributes['data-defenderId'].value
RdDEmpoignade.onAttaqueEmpoignadeValidee(game.actors.get(attackerId), game.actors.get(defenderId))
});
const attacker = RdDEmpoignade.getActorFromEventTag(event, 'data-attackerId')
const defender = RdDEmpoignade.getActorFromEventTag(event, 'data-defenderId')
if (attacker && defender) {
RdDEmpoignade.onAttaqueEmpoignadeValidee(attacker, defender)
}
})
$(html).on("click", '.empoignade-entrainer-sol', event => {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
RdDEmpoignade.entrainerAuSol(rollData)
ChatUtility.remover(chatMessage)()
});
})
$(html).on("click", '.empoignade-projeter-sol', event => {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
RdDEmpoignade.projeterAuSol(rollData)
ChatUtility.remover(chatMessage)()
});
})
$(html).on("change", '.empoignade-perte-endurance', event => {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
@@ -104,7 +113,11 @@ export class RdDEmpoignade {
RdDEmpoignade.perteEndurance(rollData, event.currentTarget.value)
ChatUtility.remover(chatMessage)()
}
});
})
}
static getActorFromEventTag(event, tag) {
return RdDEmpoignade.getActorEmpoignade(event.currentTarget.attributes[tag]?.value ?? '<inconnu>')
}
/* -------------------------------------------- */
@@ -112,32 +125,31 @@ export class RdDEmpoignade {
// TODO: autoriser la perception? la comédie/séduction?
if (RdDEmpoignade.isEmpoignadeEnCours(actor)) {
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
return true;
return true
}
return false;
return false
}
/* -------------------------------------------- */
static $storeRollEmpoignade(msg, rollData) {
RdDEmpoignade.$reduceActorToIds(rollData);
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData);
ChatUtility.setMessageData(msg, "empoignade-roll-data", RdDEmpoignade.$reduceActorToIds(rollData))
}
static $reduceActorToIds(rollData) {
rollData.attacker = { id: rollData.attacker.id };
rollData.defender = { id: rollData.defender.id };
rollData.attacker = { id: rollData.attacker.id }
rollData.defender = { id: rollData.defender.id }
return rollData
}
/* -------------------------------------------- */
static $readRollEmpoignade(msg) {
const rollData = ChatUtility.getMessageData(msg, 'empoignade-roll-data');
RdDEmpoignade.$replaceIdsWithActors(rollData);
return rollData
return RdDEmpoignade.$replaceIdsWithActors(ChatUtility.getMessageData(msg, 'empoignade-roll-data'))
}
static $replaceIdsWithActors(rollData) {
rollData.attacker = game.actors.get(rollData.attacker.id);
rollData.defender = game.actors.get(rollData.defender.id);
rollData.attacker = RdDEmpoignade.getActorEmpoignade(rollData.attacker.id)
rollData.defender = RdDEmpoignade.getActorEmpoignade(rollData.defender.id)
return rollData
}
/* -------------------------------------------- */
@@ -147,19 +159,21 @@ export class RdDEmpoignade {
/* -------------------------------------------- */
static getEmpoignadeById(actor, id) {
return actor.itemTypes[ITEM_TYPES.empoignade].find(it => it.system.empoignadeid == id)
return actor?.itemTypes[ITEM_TYPES.empoignade].find(it => it.system.empoignadeid == id)
}
/* -------------------------------------------- */
static getEmpoignade(attacker, defender) {
let emp = attacker.itemTypes[ITEM_TYPES.empoignade].find(it =>
(it.system.empoigneurid == attacker.id && it.system.empoigneid == defender.id) ||
(it.system.empoigneurid == defender.id && it.system.empoigneid == attacker.id)
)
if (emp) {
return foundry.utils.duplicate(emp);
if (attacker && defender) {
const empoignade = attacker.itemTypes[ITEM_TYPES.empoignade].find(it =>
(it.system.empoigneurid == attacker.id && it.system.empoigneid == defender.id) ||
(it.system.empoigneurid == defender.id && it.system.empoigneid == attacker.id)
)
if (empoignade) {
return foundry.utils.duplicate(empoignade)
}
}
return undefined;
return undefined
}
/* -------------------------------------------- */
@@ -180,10 +194,14 @@ export class RdDEmpoignade {
}
static isActionAutorisee(mode, attacker, defender) {
const acting = RdDEmpoignade.isActionDefenseur(mode) ? defender : attacker;
if (!defender || !attacker) {
return false
}
const acting = RdDEmpoignade.isActionDefenseur(mode) ? defender : attacker
if (acting.getUserLevel(game.user) < CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) {
ui.notifications.warn(`Vous n'êtes pas autorisé à choisir l'action de ${acting.name}`)
return false;
return false
}
return true
}
@@ -205,14 +223,11 @@ export class RdDEmpoignade {
let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
const isNouvelle = empoignade == undefined;
empoignade = empoignade ?? (await RdDEmpoignade.createEmpoignade(attacker, defender))
//console.log("W.", empoignade, defender.hasArmeeMeleeEquipee())
if ((isNouvelle || empoignade.system.pointsemp == 0) && defender.hasArmeeMeleeEquipee()) {
ChatUtility.createChatWithRollMode(
{
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-valider.hbs`, { attacker: attacker, defender: defender })
},
attacker
)
await ChatMessage.create(ChatUtility.adaptVisibility(
{ content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-valider.hbs`, { attacker: attacker, defender: defender }) },
{ actor: attacker }
))
} else {
await this.onAttaqueEmpoignadeValidee(attacker, defender)
}
@@ -264,30 +279,34 @@ export class RdDEmpoignade {
/* -------------------------------------------- */
static async onAttaqueEmpoignadeFromItem(empoignade) {
let attacker = game.actors.get(empoignade.system.empoigneurid)
let defender = game.actors.get(empoignade.system.empoigneid)
await this.onAttaqueEmpoignadeValidee(attacker, defender)
const attacker = RdDEmpoignade.getActorEmpoignade(empoignade.system.empoigneurid)
const defender = RdDEmpoignade.getActorEmpoignade(empoignade.system.empoigneid)
if (attacker && defender) {
await this.onAttaqueEmpoignadeValidee(attacker, defender)
}
}
static async onImmobilisation(attacker, empoignade) {
const defender = game.actors.get(empoignade.system.empoigneid)
const empDefenseur = defender.itemTypes[ITEM_TYPES.empoignade]
.find(it => it.system.empoignadeid == empoignade.system.empoignadeid);
await defender.updateEmbeddedDocuments('Item', [{
_id: empDefenseur.id,
'system.immobilise': true
}])
const rollData = {
mode: "immobilise",
empoignade, attacker, defender,
isEmpoignade: true,
competence: attacker.getCompetenceCorpsACorps()
const defender = RdDEmpoignade.getActorEmpoignade(empoignade.system.empoigneid)
if (defender) {
const empDefenseur = defender.itemTypes[ITEM_TYPES.empoignade]
.find(it => it.system.empoignadeid == empoignade.system.empoignadeid);
await defender.updateEmbeddedDocuments('Item', [{
_id: empDefenseur.id,
'system.immobilise': true
}])
const rollData = {
mode: "immobilise",
empoignade, attacker, defender,
isEmpoignade: true,
competence: attacker.getCompetenceCorpsACorps()
}
const msg = await ChatMessage.create({
whisper: ChatUtility.getOwners(attacker),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-immobilise.hbs`, rollData)
})
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
}
const msg = await ChatMessage.create({
whisper: ChatUtility.getOwners(attacker),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-immobilise.hbs`, rollData)
})
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
}
/* -------------------------------------------- */
@@ -304,30 +323,30 @@ export class RdDEmpoignade {
/* -------------------------------------------- */
static async $onRollEmpoignade(rollData, isNouvelle = false) {
let attacker = game.actors.get(rollData.attacker.id)
let defender = game.actors.get(rollData.defender.id)
const attacker = RdDEmpoignade.getActorEmpoignade(rollData.attacker.id)
const defender = RdDEmpoignade.getActorEmpoignade(rollData.defender.id)
if (attacker && defender) {
if (rollData.rolled.isSuccess && isNouvelle) {
RdDEmpoignade.$createEtatEmpoignade(rollData.empoignade)
}
if (rollData.rolled.isSuccess && isNouvelle) {
RdDEmpoignade.$createEtatEmpoignade(rollData.empoignade)
rollData.empoignade.isSuccess = rollData.rolled.isSuccess;
if (rollData.rolled.isPart) {
rollData.particuliere = "finesse";
}
let msg = await RdDRollResult.displayRollData(rollData, defender, 'chat-empoignade-resultat.hbs');
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
}
rollData.empoignade.isSuccess = rollData.rolled.isSuccess;
if (rollData.rolled.isPart) {
rollData.particuliere = "finesse";
}
let msg = await RdDRollResult.displayRollData(rollData, defender, 'chat-empoignade-resultat.hbs');
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
}
/* -------------------------------------------- */
static async onDefenseEmpoignade(attackerRoll, mode, competenceName = "Corps à corps", carac = "melee") {
let attacker = game.actors.get(attackerRoll.attacker.id)
let defender = game.actors.get(attackerRoll.defender.id)
const attacker = RdDEmpoignade.getActorEmpoignade(rollData.attacker.id)
const defender = RdDEmpoignade.getActorEmpoignade(rollData.defender.id)
if (!RdDEmpoignade.isActionAutorisee(mode, attacker, defender)) {
return
}
let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
if (!empoignade) {
@@ -367,7 +386,7 @@ export class RdDEmpoignade {
/* -------------------------------------------- */
static async $onRollContrerLiberer(rollData) {
let empoignade = rollData.empoignade
const empoignade = rollData.empoignade
if (rollData.mode == "contrer-empoigner" && !rollData.rolled.isSuccess) {
empoignade.system.pointsemp++
@@ -389,35 +408,40 @@ export class RdDEmpoignade {
static async $createEtatEmpoignade(empoignade) {
console.log("CREATE Empoignade", empoignade)
let defender = game.actors.get(empoignade.system.empoigneid)
let attacker = game.actors.get(empoignade.system.empoigneurid)
const attacker = RdDEmpoignade.getActorEmpoignade(empoignade.system.empoigneurid)
const defender = RdDEmpoignade.getActorEmpoignade(empoignade.system.empoigneid)
// Creer l'empoignade sur attaquant/defenseur
await attacker.creerObjetParMJ(empoignade)
await defender.creerObjetParMJ(empoignade)
if (attacker && defender) {
// Creer l'empoignade sur attaquant et defenseur
await attacker.creerObjetParMJ(empoignade)
await defender.creerObjetParMJ(empoignade)
}
}
/* -------------------------------------------- */
static async $updateEtatEmpoignade(empoignade, attacker, defender) {
const belligerants = [
attacker ?? game.actors.get(empoignade.system.empoigneurid),
defender ?? game.actors.get(empoignade.system.empoigneid)]
const removeEmp = empoignade.system.pointsemp == 0
attacker = attacker ?? RdDEmpoignade.getActorEmpoignade(empoignade.system.empoigneurid)
defender = defender ?? RdDEmpoignade.getActorEmpoignade(empoignade.system.empoigneid)
if (removeEmp) {
const emp = RdDEmpoignade.getEmpoignadeById(attacker, empoignade.system.empoignadeid)
return await attacker.deleteEmbeddedDocuments('Item', [emp.id])
}
else {
await Promise.all(
belligerants.map(async belligerant => {
const emp = RdDEmpoignade.getEmpoignadeById(belligerant, empoignade.system.empoignadeid)
return await belligerant.updateEmbeddedDocuments('Item', [{
_id: emp.id,
"system.pointsemp": empoignade.system.pointsemp,
"system.ausol": empoignade.system.ausol
}])
}))
if (attacker && defender) {
const belligerants = [attacker, defender]
const removeEmp = empoignade.system.pointsemp == 0
if (removeEmp) {
const emp = RdDEmpoignade.getEmpoignadeById(attacker, empoignade.system.empoignadeid)
return await attacker.deleteEmbeddedDocuments('Item', [emp.id])
}
else {
await Promise.all(
belligerants.map(async belligerant => {
const emp = RdDEmpoignade.getEmpoignadeById(belligerant, empoignade.system.empoignadeid)
return await belligerant.updateEmbeddedDocuments('Item', [{
_id: emp.id,
"system.pointsemp": empoignade.system.pointsemp,
"system.ausol": empoignade.system.ausol
}])
}))
}
}
}
@@ -425,19 +449,21 @@ export class RdDEmpoignade {
static async $deleteEmpoignade(empoignade) {
console.log("DELETE Empoignade", empoignade)
const defender = game.actors.get(empoignade.system.empoigneid)
const emp = RdDEmpoignade.getEmpoignadeById(defender, empoignade.system.empoignadeid)
await defender.deleteEmbeddedDocuments('Item', [emp.id])
const defender = RdDEmpoignade.getActorEmpoignade(empoignade.system.empoigneid)
if (defender) {
const emp = RdDEmpoignade.getEmpoignadeById(defender, empoignade.system.empoignadeid)
await defender.deleteEmbeddedDocuments('Item', [emp.id])
}
}
/* -------------------------------------------- */
static async entrainerAuSol(rollData) {
let attacker = game.actors.get(rollData.attacker.id)
let defender = game.actors.get(rollData.defender.id)
const attacker = RdDEmpoignade.getActorEmpoignade(rollData.attacker.id)
const defender = RdDEmpoignade.getActorEmpoignade(rollData.defender.id)
if (!RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
return
}
let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
const empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
empoignade.system.ausol = true
await this.$updateEtatEmpoignade(empoignade)
@@ -445,14 +471,14 @@ export class RdDEmpoignade {
await attacker.setEffect(STATUSES.StatusProne, true);
await defender.setEffect(STATUSES.StatusProne, true);
let msg = await RdDRollResult.displayRollData(rollData, attacker, 'chat-empoignade-entrainer-sol.hbs');
const msg = await RdDRollResult.displayRollData(rollData, attacker, 'chat-empoignade-entrainer-sol.hbs');
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
}
/* -------------------------------------------- */
static async projeterAuSol(rollData) {
let attacker = game.actors.get(rollData.attacker.id)
let defender = game.actors.get(rollData.defender.id)
const attacker = RdDEmpoignade.getActorEmpoignade(rollData.attacker.id)
const defender = RdDEmpoignade.getActorEmpoignade(rollData.defender.id)
if (!RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
return
}
@@ -467,8 +493,8 @@ export class RdDEmpoignade {
/* -------------------------------------------- */
static async perteEndurance(rollData, perteMode) {
let attacker = game.actors.get(rollData.attacker.id)
let defender = game.actors.get(rollData.defender.id)
const attacker = RdDEmpoignade.getActorEmpoignade(rollData.attacker.id)
const defender = RdDEmpoignade.getActorEmpoignade(rollData.defender.id)
if (perteMode == "none" || !RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
return
}
@@ -501,11 +527,11 @@ export class RdDEmpoignade {
/* -------------------------------------------- */
static async deleteLinkedEmpoignade(actorId, empoignade) {
let actorDeleteId = (actorId == empoignade.system.empoigneurid) ? empoignade.system.empoigneid : empoignade.system.empoigneurid
let actor = game.actors.get(actorDeleteId)
let emp = this.getEmpoignadeById(actor, empoignade.system.empoignadeid)
if (emp) {
await actor.deleteEmbeddedDocuments('Item', [emp.id])
const actorDeleteId = (actorId == empoignade.system.empoigneurid) ? empoignade.system.empoigneid : empoignade.system.empoigneurid
const actor = RdDEmpoignade.getActorEmpoignade(actorDeleteId)
const empoignadeOpposant = this.getEmpoignadeById(actor, empoignade.system.empoignadeid)
if (actor && empoignadeOpposant) {
await actor.deleteEmbeddedDocuments('Item', [empoignadeOpposant.id])
}
}

View File

@@ -101,7 +101,7 @@ export class RdDHotbar {
}
/** Roll macro */
static rollMacro(itemName, itemType, categorieArme = 'competence') {
static rollMacro(itemName, itemType, maniement = 'competence') {
const speaker = ChatMessage.getSpeaker();
let actor;
if (speaker.token) actor = game.actors.tokens[speaker.token];
@@ -117,10 +117,10 @@ export class RdDHotbar {
// Trigger the item roll
switch (item.type) {
case ITEM_TYPES.arme:
return actor.rollArme(item, categorieArme);
return actor.rollArme(item, maniement);
case ITEM_TYPES.competence:
if (item.isCorpsACorps()) {
switch (categorieArme) {
switch (maniement) {
case PUGILAT:
return actor.rollArme(RdDItemArme.pugilat(actor));
case EMPOIGNADE:
@@ -130,7 +130,7 @@ export class RdDHotbar {
return actor.rollCompetence(item);
case ITEM_TYPES.competencecreature:
return item.system.iscombat
? actor.rollArme(item, categorieArme)
? actor.rollArme(item, maniement)
: actor.rollCompetence(item);
}

View File

@@ -94,6 +94,7 @@ import ChatRollResult from "./roll/chat-roll-result.mjs"
import ExportPdf from "./actor/export-pdf/export-pdf.mjs"
import { DialogFlushByDate } from "./chat/dialog-flush-by-date.mjs"
import { Remote } from "./remote.mjs"
import { RdDActiveEffect } from "./effect/base-active-effect.js"
/**
* RdD system
@@ -199,6 +200,7 @@ export class SystemReveDeDragon {
// Define custom Entity classes
console.log(`Initializing Reve de Dragon Documents`)
CONFIG.Actor.documentClass = RdDBaseActor
CONFIG.ActiveEffect.documentClass = RdDActiveEffect
CONFIG.Item.documentClass = RdDItem
CONFIG.Item.dataModels = {
monnaie: models.RdDModelMonnaie,

View File

@@ -4,12 +4,10 @@ import { renderTemplate } from "./constants.js";
export class RdDRollResult {
static async displayRollData(rollData, actor = undefined, template = 'chat-resultat-general.hbs') {
const chatMessage = await ChatUtility.createChatWithRollMode(
return await ChatMessage.create(ChatUtility.adaptVisibility(
{ content: await RdDRollResult.buildRollDataHtml(rollData, template) },
actor,
rollData.current?.rollmode?.key
)
return chatMessage
{ actor: actor, rollMode: rollData.current?.rollmode?.key }
))
}
static async buildRollDataHtml(rollData, template = 'chat-resultat-general.hbs') {

View File

@@ -34,9 +34,9 @@ export class RdDRollTables {
}
/* -------------------------------------------- */
static async getCompetence(toChat = false) {
static async getCompetence(toChat = false, rollMode = "gmroll") {
if (toChat == 'liste') {
return await RdDRollTables.listOrRoll('competences', 'Item', ['competence'], toChat, it => 1);
return await RdDRollTables.listOrRoll('competences', 'Item', ['competence'], toChat, rollMode, it => 1);
}
else {
return await RdDRollTables.drawItemFromRollTable("Détermination aléatoire de compétence", toChat);
@@ -44,56 +44,58 @@ export class RdDRollTables {
}
/* -------------------------------------------- */
static async getSouffle(toChat = false) {
return await RdDRollTables.listOrRoll('souffles-de-dragon', 'Item', ['souffle'], toChat);
static async getSouffle(toChat = false, rollMode = "gmroll") {
return await RdDRollTables.listOrRoll('souffles-de-dragon', 'Item', ['souffle'], toChat, rollMode);
}
/* -------------------------------------------- */
static async getQueue(toChat = false) {
return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', ['queue'], toChat);
static async getQueue(toChat = false, rollMode = "gmroll") {
return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', ['queue'], toChat, rollMode);
}
static async getDesirLancinant(toChat = false) {
return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', ['queue'], toChat,
static async getDesirLancinant(toChat = false, rollMode = "gmroll") {
return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', ['queue'], toChat, rollMode,
it => it.system.frequence,
it => it.system.categorie == 'lancinant');
}
static async getIdeeFixe(toChat = false) {
return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', ['queue'], toChat,
static async getIdeeFixe(toChat = false, rollMode = "gmroll") {
return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', ['queue'], toChat, rollMode,
it => it.system.frequence,
it => it.system.categorie == 'ideefixe');
}
/* -------------------------------------------- */
static async getTeteHR(toChat = false) {
return await RdDRollTables.listOrRoll('tetes-de-dragon-pour-haut-revants', 'Item', ['tete'], toChat);
static async getTeteHR(toChat = false, rollMode = "gmroll") {
return await RdDRollTables.listOrRoll('tetes-de-dragon-pour-haut-revants', 'Item', ['tete'], toChat, rollMode);
}
/* -------------------------------------------- */
static async getTete(toChat = false) {
return await RdDRollTables.listOrRoll('tetes-de-dragon-pour-tous-personnages', 'Item', ['tete'], toChat);
static async getTete(toChat = false, rollMode = "gmroll") {
return await RdDRollTables.listOrRoll('tetes-de-dragon-pour-tous-personnages', 'Item', ['tete'], toChat, rollMode);
}
/* -------------------------------------------- */
static async getOmbre(toChat = false) {
return await RdDRollTables.listOrRoll('ombres-de-thanatos', 'Item', ['ombre'], toChat);
static async getOmbre(toChat = false, rollMode = "gmroll") {
return await RdDRollTables.listOrRoll('ombres-de-thanatos', 'Item', ['ombre'], toChat, rollMode);
}
/* -------------------------------------------- */
static async getTarot(toChat = true) {
return await RdDRollTables.listOrRoll('tarot-draconique', 'Item', ['tarot'], toChat);
static async getTarot(toChat = true, rollMode = "gmroll") {
return await RdDRollTables.listOrRoll('tarot-draconique', 'Item', ['tarot'], toChat, rollMode);
}
/* -------------------------------------------- */
static async listOrRoll(compendium, type, subTypes, toChat, itemFrequence = it => it.system.frequence, filter = it => true) {
static async listOrRoll(compendium, type, subTypes, toChat, rollMode,
itemFrequence = it => it.system.frequence,
filter = it => true) {
const table = new CompendiumTable(compendium, type, subTypes);
if (toChat == 'liste') {
return await table.toChatMessage(itemFrequence, filter);
}
const row = await table.getRandom(itemFrequence, filter);
if (row) {
await CompendiumTableHelpers.tableRowToChatMessage(row, type);
await CompendiumTableHelpers.tableRowToChatMessage(row, type, { rollMode: rollMode });
return row.document;
}
return undefined;

View File

@@ -1137,12 +1137,12 @@ export class RdDTMRDialog extends Dialog {
if (!token) {
return
}
if (this.demiReve === token && this.isDemiReveCache()) {
if (this.isDemiReveCache() && [EffetsDraconiques.rencontre.code(), EffetsDraconiques.demiReve.code()].includes(token.code)) {
return
}
this.pixiTMR.positionToken(token);
this.pixiTMR.positionToken(token)
if (!this.allTokens.includes(token)) {
this.allTokens.push(token);
this.allTokens.push(token)
}
}
}

View File

@@ -147,7 +147,7 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/actor/taches.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/oeuvres.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/oeuvre.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/jeus.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/jeux.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/alchimie.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/astrologie.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/chirurgie.hbs',
@@ -483,7 +483,7 @@ export class RdDUtility {
static filterItemsPerTypeForSheet(formData, itemTypes) {
Object.values(ITEM_TYPES).forEach(t => {
formData[t + 's'] = Misc.arrayOrEmpty(itemTypes[t])
formData[RdDItem.itemTypePluriel(t)] = Misc.arrayOrEmpty(itemTypes[t])
itemTypes[t].forEach(item => item.actions = item.itemActions())
})
@@ -680,7 +680,7 @@ export class RdDUtility {
encaissement.dmg = dmg
if (ReglesOptionnelles.isUsing('localisation-aleatoire')) {
encaissement.dmg.loc = dmg.loc ?? await RdDUtility.getLocalisation(targetActor.type)
encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps;'
encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps'
}
else {
encaissement.dmg.loc = { label: '' }
@@ -689,9 +689,9 @@ export class RdDUtility {
encaissement.armure = armure
encaissement.penetration = dmg.penetration
encaissement.total = jetTotal
encaissement.vie = await RdDUtility._evaluatePerte(encaissement.vie, over20);
encaissement.endurance = await RdDUtility._evaluatePerte(encaissement.endurance, over20);
return encaissement;
encaissement.vie = await RdDUtility._evaluatePerte(encaissement.vie, over20)
encaissement.endurance = await RdDUtility._evaluatePerte(encaissement.endurance, over20)
return encaissement
}
/* -------------------------------------------- */

View File

@@ -43,13 +43,13 @@ export default class ChatRollResult {
async display(roll, impacts) {
this.prepareDisplay(roll)
const chatMessage = await ChatUtility.createChatWithRollMode(
const chatMessage = await ChatMessage.create(ChatUtility.adaptVisibility(
{
content: await this.buildRollHtml(roll)
},
roll.active.actor,
roll.current?.rollmode?.key
)
))
await this.saveChatMessageRoll(chatMessage, roll, impacts)
return chatMessage
@@ -105,8 +105,8 @@ export default class ChatRollResult {
if (attaque &&
(roll.rolled.isEchec || !roll.current.defense.isEsquive) &&
(attaque.particuliere == 'force' || 'charge' == attaque.tactique?.key)) {
const taille = defender.system.carac.taille.value
const impact = attacker.system.carac.force.value + roll.attackerRoll?.dmg.dmgArme
const taille = defender.getTaille()
const impact = attacker.getForce() + roll.attackerRoll?.dmg.dmgArme
return {
raison: 'charge' == attaque.tactique?.key ? 'charge' : 'particulière en force',
taille: taille,

View File

@@ -218,7 +218,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
foundry.applications.handlebars.loadTemplates(ALL_ROLL_TYPES.map(m => m.chatResultTemplate))
foundry.applications.handlebars.loadTemplates(ROLL_PARTS.map(p => p.template))
ROLL_PARTS.forEach(p => p.onReady())
ROLL_PARTS.forEach(p => p.onReady(ROLL_PARTS))
Handlebars.registerHelper('roll-centered-array', (base, show) => {
show = Math.abs(show)
@@ -380,7 +380,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
this.rollData = rollData
this.rollOptions = {
callbacks: [
async r => await r.active.actor.appliquerAjoutExperience(r),
async r => await r.active.actor.ajoutExperience(r),
async r => await r.active.actor.appliquerAppelMoral(r),
...(rollOptions.callbacks ?? [])
],
@@ -479,16 +479,13 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
RollBasicParts.loadSurprises(rollData, this.getSelectedType().code)
rollData.type.label = this.getSelectedType()?.title(rollData)
const visibleRollParts = this.getActiveParts()
visibleRollParts.forEach(p => p.applyExternalImpacts(visibleRollParts, rollData))
this.setSpecialComp(visibleRollParts);
visibleRollParts.forEach(p => p.prepareContext(rollData))
this.getActiveParts().forEach(p => p.applyExternalImpacts(this.getActiveParts(), rollData))
this.setSpecialComp(this.getActiveParts());
this.getActiveParts().forEach(p => p.prepareContext(rollData))
RollDialog.calculAjustement(rollData)
const templates = visibleRollParts.map(p => p.toTemplateData())
const templates = this.getActiveParts().map(p => p.toTemplateData())
const context = await super._prepareContext()
return foundry.utils.mergeObject(
{
@@ -569,7 +566,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
}
async defaultCallback(roll, rolled) {
await roll.active.actor.appliquerAjoutExperience(roll)
await roll.active.actor.ajoutExperience(roll)
await roll.active.actor.appliquerAppelMoral(roll)
}

View File

@@ -1,4 +1,5 @@
import { Grammar } from "../grammar.js"
import { CARACS } from "../rdd-carac.js"
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"
import { ROLL_TYPE_SORT } from "./roll-constants.mjs"
import { RollPartCheckbox } from "./roll-part-checkbox.mjs"
@@ -20,7 +21,7 @@ export class RollPartAstrologique extends RollPartCheckbox {
}
isJetChance(rollData) {
return Grammar.includesLowerCaseNoAccent(rollData.current.carac.key, 'chance')
return Grammar.includesLowerCaseNoAccent(rollData.current.carac.key, CARACS.CHANCE)
}
$isUsingAstrologie() {

View File

@@ -52,11 +52,13 @@ export class RollPartAttaque extends RollPartSelect {
restore(rollData) {
const saved = this.getSaved(rollData) ?? {}
this.setCurrent(rollData, {
key: saved.key,
tactique: saved.tactique,
dmg: saved.dmg
})
if (saved.key) {
this.setCurrent(rollData, {
key: saved.key,
tactique: saved.tactique,
dmg: saved.dmg
})
}
}
store(rollData, targetData) {
@@ -70,9 +72,11 @@ export class RollPartAttaque extends RollPartSelect {
findAttaque(attaques, saved) {
return attaques.find(at => at.arme.id == saved?.arme?.id &&
at.comp.id == saved?.comp?.id
)
return attaques.find(it => it.key == saved.key) ??
attaques.find(it => it.arme.id == (saved?.arme?.id ?? it.arme.id)
&& it.comp.id == (saved?.comp?.id ?? it.comp.id)
&& it.main == (saved?.main ?? it.main)
)
}
choices(refs) { return refs.attaques }

View File

@@ -41,7 +41,7 @@ export class RollPartCheckbox extends RollPart {
}
getCheckboxLabelAjustement(rollData) {
return `${this.getCheckboxIcon(rollData)} ${this.getRefs(rollData).label}`
return `${this.getCheckboxIcon(rollData)} ${this.getCheckboxLabel(rollData)}`
}
async _onRender(rollDialog, context, options) {

View File

@@ -1,7 +1,9 @@
import { Grammar } from "../grammar.js"
import { Misc } from "../misc.js"
import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_DIFF } from "./roll-part-diff.mjs"
import { RollPartSelect } from "./roll-part-select.mjs"
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
export const PART_COMP = "comp"
@@ -15,15 +17,21 @@ export class RollPartComp extends RollPartSelect {
get name() { return 'Compétences' }
get section() { return ROLLDIALOG_SECTION.COMP }
onReady(rollParts) {
this.rollPartCarac = rollParts.find(it => it.code == PART_CARAC)
this.rollPartDiff = rollParts.find(it => it.code == PART_DIFF)
}
loadRefs(rollData) {
const refs = this.getRefs(rollData)
const selected = this.getSelected(rollData)
const all = this.$getActorComps(rollData)
if (selected.forced) {
refs.all = all.filter(comp => Grammar.equalsInsensitive(comp.label, selected.key))
const selectedComp = selected.key
if (selected.forced && selectedComp) {
refs.all = all.filter(comp => Grammar.equalsInsensitive(comp.label, selectedComp))
if (refs.all.length == 0) {
if (selected.key.length > 0) {
refs.all = all.filter(comp => Grammar.includesLowerCaseNoAccent(comp.label, selected.key))
if (selected.key && selected.key.length > 0) {
refs.all = all.filter(comp => Grammar.includesLowerCaseNoAccent(comp.label, selectedComp))
}
else {
refs.all = all.filter(comp => comp == SANS_COMPETENCE)
@@ -35,6 +43,13 @@ export class RollPartComp extends RollPartSelect {
}
refs.comps = refs.all
this.$selectComp(rollData)
if (rollData.type.current == PART_COMP && selectedComp) {
const current = this.getCurrent(rollData)
const selectedCarac = RollPart.getSelectedPart(rollData, PART_CARAC)
const selectedDiff = RollPart.getSelectedPart(rollData, PART_DIFF)
this.rollPartCarac.selectByKey(rollData, selectedCarac?.key ?? current.comp.system.defaut_carac)
this.rollPartDiff.setDiff(rollData, selectedDiff?.value ?? current.comp.system.default_diffLibre)
}
}
choices(refs) { return refs.comps }
@@ -71,6 +86,7 @@ export class RollPartComp extends RollPartSelect {
refs.comps.sort(sorting)
}
this.$selectComp(rollData)
}
prepareContext(rollData) {

View File

@@ -10,7 +10,7 @@ export class RollPartConditions extends RollPart {
settingMin() { return RollPart.settingKey(this, 'min') }
settingMax() { return RollPart.settingKey(this, 'max') }
onReady() {
onReady(rollParts) {
game.settings.register(SYSTEM_RDD, this.settingMin(),
{
name: "Malus maximal de conditions",
@@ -65,12 +65,7 @@ export class RollPartConditions extends RollPart {
async _onRender(rollDialog, context, options) {
const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)
input?.addEventListener("input", e => this.onInputChange(e, rollDialog))
}
onInputChange(event, rollDialog) {
this.getCurrent(rollDialog.rollData).value = parseInt(event.currentTarget.value)
rollDialog.render()
input?.addEventListener("input", e => this.onNumericInputChange(e, rollDialog))
}
}

View File

@@ -9,7 +9,7 @@ import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
export const PART_CUISINE = "cuisine"
export class RollPartCuisine extends RollPartSelect {
onReady() {
onReady(rollParts) {
foundry.applications.handlebars.loadTemplates({ 'roll-oeuvre-recettecuisine': `systems/foundryvtt-reve-de-dragon/templates/roll/roll-oeuvre-recettecuisine.hbs` })
}
@@ -43,14 +43,13 @@ export class RollPartCuisine extends RollPartSelect {
const recettes = actor.items
.filter(it => it.type == ITEM_TYPES.recettecuisine)
.map(RollPartCuisine.$extractPreparationRecette)
.map(it => RollPartCuisine.$extractPreparationRecette(refs.cuisine, it))
const ingredientsBruts = actor.items
.filter(it => it.getUtilisationCuisine() == 'brut')
.map(RollPartCuisine.$extractPreparationBrut)
.map(it => RollPartCuisine.$extractPreparationBrut(refs.cuisine, it))
refs.preparations = [RollPartCuisine.$preparationBasique(), ...recettes, ...ingredientsBruts]
refs.preparations.forEach(p => p.comp = refs.cuisine)
refs.preparations = [RollPartCuisine.$preparationBasique(refs.cuisine), ...recettes, ...ingredientsBruts]
if (refs.preparations.length > 0) {
this.$selectPreparation(rollData)
this.$restoreSavedOptions(rollData)
@@ -73,7 +72,7 @@ export class RollPartCuisine extends RollPartSelect {
choices(refs) { return refs.preparations }
static $preparationBasique() {
static $preparationBasique(cuisine) {
return {
key: '',
label: "Improvisation du moment",
@@ -85,10 +84,12 @@ export class RollPartCuisine extends RollPartSelect {
proportionsMax: 50,
value: 0,
fabriquer: false,
qualite: cuisine.system.niveau,
comp: cuisine,
}
}
static $extractPreparationRecette(recette) {
static $extractPreparationRecette(cuisine, recette) {
const proportions = recette.system.sust ?? 1
return {
key: recette.id,
@@ -102,10 +103,12 @@ export class RollPartCuisine extends RollPartSelect {
value: -recette.system.niveau,
recette: recette,
fabriquer: true,
qualite: recette.system.niveau,
comp: cuisine,
}
}
static $extractPreparationBrut(ingredient) {
static $extractPreparationBrut(cuisine, ingredient) {
return {
key: ingredient.id,
label: ingredient.name + ' cuisiné',
@@ -118,6 +121,8 @@ export class RollPartCuisine extends RollPartSelect {
value: 0,
ingredient: ingredient,
fabriquer: true,
qualite: cuisine.system.niveau,
comp: cuisine,
}
}
@@ -150,7 +155,7 @@ export class RollPartCuisine extends RollPartSelect {
this.$selectPreparation(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.render()
})
checkboxFabriquer?.addEventListener("change", e => {
current.fabriquer = e.currentTarget.checked
})

View File

@@ -73,12 +73,7 @@ export class RollPartDiff extends RollPart {
async _onRender(rollDialog, context, options) {
const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)
input?.addEventListener("input", e => this.onInputChange(e, rollDialog))
}
onInputChange(event, rollDialog) {
this.getCurrent(rollDialog.rollData).value = parseInt(event.currentTarget.value)
rollDialog.render()
input?.addEventListener("input", e => this.onNumericInputChange(e, rollDialog))
}
}

View File

@@ -15,18 +15,32 @@ export class RollPartEncTotal extends RollPartCheckbox {
&& RdDItemCompetence.isMalusEncombrementTotal(rollData.current.comp?.key)
}
loadRefs(rollData) {
const refs = this.getRefs(rollData)
refs.malusEnc = - Math.floor(rollData.active.actor.getEncTotal())
const current = this.getCurrent(rollData)
current.value = refs.malusEnc
}
async _onRender(rollDialog, context, options) {
super._onRender(rollDialog, context, options)
const inputMalusEnc = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="malusenc"]`)
inputMalusEnc?.addEventListener("change", e => {
this.getCurrent(rollDialog.rollData).value = parseInt(e.currentTarget.value)
const malusEnc = Math.floor(e.currentTarget.value)
const rollData = rollDialog.rollData
const refs = this.getRefs(rollData)
const current = this.getCurrent(rollData)
if (refs.malusEnc == current.value) {
current.value = malusEnc
}
refs.malusEnc = malusEnc
rollDialog.render()
})
}
getCheckboxIcon(rollData) { return `<img src="${RDD_CONFIG.icons.surenc}">` }
getCheckboxLabel(rollData) { return "Enc. total" }
getCheckboxValue(rollData) { return - rollData.active.actor.getEncTotal() }
getCheckboxValue(rollData) { return this.getCurrent(rollData).value }
}

View File

@@ -24,7 +24,7 @@ const ARTS = [
]
export class RollPartOeuvre extends RollPartSelect {
onReady() {
onReady(rollParts) {
ARTS.forEach(art => art.label = Misc.typeName('Item', art.type))
ARTS.map(it => `roll-oeuvre-${it.type}`)
.forEach(art =>

View File

@@ -12,7 +12,7 @@ export const PART_SORT = "sort"
export class RollPartSort extends RollPartSelect {
onReady() {
onReady(rollParts) {
// TODO: utiliser un hook pour écouter les déplacements dans les TMRs?
}
@@ -28,7 +28,8 @@ export class RollPartSort extends RollPartSelect {
this.setCurrent(rollData, {
key: saved.key,
isReserve: saved.isReserve,
ptreve: saved.ptreve
ptreve: saved.ptreve,
value: saved.value,
})
}
@@ -37,7 +38,8 @@ export class RollPartSort extends RollPartSelect {
this.setSaved(targetData, {
key: current.key,
isReserve: current.isReserve,
ptreve: current.ptreve
ptreve: current.ptreve,
value: current.value,
})
}
@@ -98,7 +100,7 @@ export class RollPartSort extends RollPartSelect {
const sort = { label: current.label, value: current.value }
const reserve = current.isReserve ? [{ label: `Mise en réserve en ${this.getCoord(rollData)}` }] : []
const bonusCase = current.bonusCase ? [{ label: `Bonus case +${current.bonusCase}%` }] : []
const reve = { label: `Rêve ${current.ptreve}` }
const reve = { label: `Dépense de rêve ${current.ptreve}` }
return [sort, ...bonusCase, reve, ...reserve]
}
return []
@@ -106,9 +108,12 @@ export class RollPartSort extends RollPartSelect {
$selectSort(rollData, values) {
const current = this.selectByKey(rollData, values.key)
if (values.ptreve) {
if (values.ptreve != undefined) {
current.ptreve = values.ptreve
}
if (current.isDiffVariable && values.value != undefined) {
current.value = values.value
}
if (values.isReserve != undefined) {
current.isReserve = values.isReserve
}

View File

@@ -1,5 +1,3 @@
import { ALL_ROLL_TYPES } from "./roll-dialog.mjs"
export const ROLLDIALOG_SECTION = {
ACTION: 'action',
CARAC: 'carac',
@@ -7,12 +5,11 @@ export const ROLLDIALOG_SECTION = {
CHOIX: 'choix',
CONDITIONS: 'conditions',
AJUSTEMENTS: 'ajustements',
}
}
export class RollPart {
static settingKey(rollPart, key) { return `roll-part-${rollPart.code}.${key}` }
get code() { throw new Error(`Pas dse code définie pour ${this}`) }
get name() { return this.code }
/** la section de la fenêtre ou le paramêtre apparaît */
@@ -20,30 +17,37 @@ export class RollPart {
get priority() { return 0 /* TODO */ }
/** le template handlebars pour affichage */
get template() { return `systems/foundryvtt-reve-de-dragon/templates/roll/roll-part-${this.code}.hbs` }
static getSelectedPart(rollData, code) {
return rollData.selected[code] ?? {}
}
static setSelectedPart(rollData, code, saved) {
rollData.selected[code] = saved
}
/** l'acteur actif du jet */
getActor(rollData) { return rollData.active.actor }
/** le conteneur de données du RollPart */
getRefs(rollData) {
return rollData.refs[this.code]
}
}
/** les informations de sélection du paramètre */
getCurrent(rollData) {
return rollData.current[this.code]
}
}
setCurrent(rollData, current) {
rollData.current[this.code] = current
}
}
/** les informations minimales représentant la sélection dans le rollData permettant de restaurer la fenêtre */
getSelected(rollData) { return this.getSaved(rollData) }
getSaved(rollData) {
return rollData.selected[this.code] ?? {}
}
return RollPart.getSelectedPart(rollData, this.code)
}
setSaved(rollData, saved) {
rollData.selected[this.code] = saved
}
RollPart.setSelectedPart(rollData, this.code, saved)
}
restore(rollData) { }
@@ -75,7 +79,7 @@ export class RollPart {
isValid(rollData) { return true }
visible(rollData) { return true }
onReady() { }
onReady(rollParts) { }
loadRefs(rollData) { }
prepareContext(rollData) { }
@@ -103,4 +107,13 @@ export class RollPart {
async _onRender(rollDialog, context, options) { }
getHooks() { return [] }
onNumericInputChange(event, rollDialog, setValue = value => this.getCurrent(rollDialog.rollData).value = value) {
if (isNaN(event.currentTarget.value) || event.currentTarget.value == "") {
return
}
setValue(parseInt(event.currentTarget.value))
rollDialog.render()
}
}

View File

@@ -21,9 +21,7 @@ export class RollTypeCuisine extends RollType {
getResult(rollData, impacts) {
const current = rollData.current[PART_CUISINE]
const diff = -current.value
const cuisine = rollData.refs[PART_CUISINE].cuisine
const qualite = rollData.rolled.ptQualite + (rollData.rolled.isSuccess ? diff : Math.min(diff, cuisine.system.niveau))
const qualite = rollData.rolled.ptQualite + current.qualite
const result = {
qualite: qualite,
@@ -49,6 +47,7 @@ export class RollTypeCuisine extends RollType {
}
return result
}
onApplyImpacts(roll, impacts) {
if (roll.result.plat) {
// le plat n'est pas créé immédiatement, il faut donc retrouver l'id

View File

@@ -5,8 +5,6 @@ const DEFAULT_DIFF_TYPES = [DIFF.LIBRE, DIFF.IMPOSEE, DIFF.DEFAUT]
export class RollType {
onReady() { }
get code() { throw new Error(`Pas de code défini pour ${this}`) }
get name() { return this.code }
get icon() { return `systems/foundryvtt-reve-de-dragon/assets/actions/${this.code}.svg` }

View File

@@ -25,6 +25,7 @@ const listeReglesOptionnelles = [
{ group: 'Affichage', name: 'afficher-colonnes-reussite', descr: "Afficher le nombre de colonnes de réussite ou d'échec", default: false },
{ group: 'Affichage', name: 'afficher-prix-joueurs', descr: "Afficher le prix de l'équipement des joueurs", uniquementJoueur: true},
{ group: 'Affichage', name: 'afficher-table-source', descr: "Afficher la table d'origine des tirages aléatoires", default: false },
{ group: 'Confirmations', name: 'confirmer-combat-sans-cible', descr: "Confirmer avant une attaque sans cible", scope: "client"},
{ group: 'Confirmations', name: 'confirmation-tmr', descr: "Confirmer pour monter dans les TMR", scope: "client"},

View File

@@ -4,6 +4,7 @@ import { Grammar } from "../grammar.js";
import { RdDItem } from "../item.js";
import { Misc } from "../misc.js";
import { RdDDice } from "../rdd-dice.js";
import { ReglesOptionnelles } from "./regles-optionnelles.js";
const COMPENDIUM_SETTING_PREFIX = 'compendium-';
@@ -289,24 +290,28 @@ export class CompendiumTableHelpers {
}
/* -------------------------------------------- */
static async tableRowToChatMessage(row, type, options = { showSource: true }) {
static async tableRowToChatMessage(row, type, options = {}) {
if (options.showSource == undefined){
options.showSource = ReglesOptionnelles.isUsing('afficher-table-source')
}
if (!row) {
return;
return
}
const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table-roll.hbs', {
roll: row.roll,
document: row.document,
typeName: Misc.typeName(type, row.document?.type ?? 'objet'),
isGM: game.user.isGM,
options
});
const messageData = {
user: game.user.id,
rolls: [row.roll],
sound: CONFIG.sounds.dice,
content: flavorContent
};
await ChatUtility.createChatWithRollMode(messageData)
options: { showSource: options.showSource }
})
await ChatMessage.create(ChatUtility.adaptVisibility(
{
user: game.user.id,
rolls: [row.roll],
sound: CONFIG.sounds.dice,
content: flavorContent
},
{ rollMode: options.rollMode }))
}
/* -------------------------------------------- */
@@ -316,13 +321,14 @@ export class CompendiumTableHelpers {
typeName: typeName ?? Misc.typeName(type, subTypes[0]),
table,
isGM: game.user.isGM,
});
const messageData = {
user: game.user.id,
whisper: [game.user],
content: flavorContent
};
await ChatUtility.createChatWithRollMode(messageData)
})
await ChatMessage.create(ChatUtility.adaptVisibility(
{
user: game.user.id,
whisper: [game.user],
content: flavorContent
}
))
}
}

View File

@@ -107,7 +107,7 @@ export class AppAstrologie extends Application {
const detail = foundry.utils.duplicate(nombreAstral);
const timestamp = new RdDTimestamp({ indexDate: nombreAstral.index });
detail.date = { mois: timestamp.mois, jour: timestamp.jour + 1 };
detail.lectures.forEach(lecture => lecture.actorName = game.actors.get(lecture.actorId).name ?? "Inconnu");
detail.lectures.forEach(lecture => lecture.actorName = game.actors.get(lecture.actorId)?.getAlias() ?? "Inconnu");
return detail;
}

View File

@@ -9,10 +9,10 @@ export class DialogStress extends Dialog {
immediat: false,
actors: game.actors.filter(actor => actor.isPersonnageJoueur())
.map(actor => ({
id: actor.id,
name: actor.name,
selected: true
})
id: actor.id,
name: actor.name,
selected: true
})
)
};
@@ -22,7 +22,8 @@ export class DialogStress extends Dialog {
}
constructor(dialogData, html) {
const options = { classes: ["DialogStress"],
const options = {
classes: ["DialogStress"],
width: 400,
height: 'fit-content',
'z-index': 99999
@@ -49,9 +50,12 @@ export class DialogStress extends Dialog {
const stress = Number(this.html.find("form.rdddialogstress input[name='stress']").val());
const compteur = (this.html.find("form.rdddialogstress input[name='immediat']").prop("checked")) ? 'experience' : 'stress';
this.dialogData.actors.filter(it => it.selected)
.map(it => game.actors.get(it.id))
.forEach(async actor => await actor.distribuerStress(compteur, stress, motif));
await Promise.all(
this.dialogData.actors.filter(it => it.selected)
.map(actor => game.actors.get(actor.id))
.filter(actor => actor != undefined)
.map(actor => actor.distribuerStress(compteur, stress, motif))
)
}
async onSelectActor(event) {

View File

@@ -10,13 +10,24 @@ export class Targets {
return Targets.listTargets().length > 0;
}
static getTokenData( actor, tokenId, target = undefined) {
if ( target){
return Targets.extractTokenData(target)
}
const token = canvas.tokens.get(tokenId);
return token == undefined
? Targets.buildActorTokenData(tokenId, actor)
: Targets.extractTokenData(token);
}
static extractTokenData(target) {
return {
id: target?.id,
name: target?.document.name,
img: target?.document.texture.src ?? target?.actor.img ?? 'icons/svg/mystery-man.svg'
}
}
}
}
static extractActorData(actor) {
return {
@@ -27,7 +38,7 @@ export class Targets {
}
static buildActorTokenData(tokenId, actor) {
return { id: tokenId, name: actor.name, img: actor.img ?? 'icons/svg/mystery-man.svg' };
return { id: tokenId, name: actor?.name?? "pas d'acteur", img: actor?.img ?? 'icons/svg/mystery-man.svg' };
}
static isTargetEntite(target) {

View File

@@ -359,7 +359,7 @@ export class RdDCalendrier extends Application {
// Gestion expérience (si existante)
request.competence = actor.getCompetence('Astrologie')
request.selectedCarac = actor.system.carac["vue"];
actor.appliquerAjoutExperience(request, 'hide');
actor.ajoutExperience(request, 'hide');
}
}
else {

View File

@@ -38,7 +38,7 @@ export class TMRRencontres {
const frequence = it => it.system.frequence[tmrType];
const row = await this.table.getRandom(frequence, filtreMauvaise, forcedRoll);
if (row) {
await CompendiumTableHelpers.tableRowToChatMessage(row, 'Item', { showSource: false });
await CompendiumTableHelpers.tableRowToChatMessage(row, 'Item', { showSource: false, rollMode: "gmroll" });
}
return row?.document;

View File

@@ -90,21 +90,22 @@ export class Draconique {
*/
token(pixiTMR, linkData, coordTMR, type = undefined) {
const tooltip = this.tooltip(linkData);
return this._createToken(pixiTMR, linkData, coordTMR, type, tooltip);
return this._createToken(pixiTMR, linkData, coordTMR, type, tooltip)
}
tokens(pixiTMR, linkData, coordTMR, type = undefined) {
tokens(pixiTMR, linkData, coordTMR, code = undefined) {
const tooltip = this.tooltip(linkData);
return [this._createToken(pixiTMR, linkData, coordTMR, type, tooltip)];
return [this._createToken(pixiTMR, linkData, coordTMR, code, tooltip)]
}
_createToken(pixiTMR, linkData, coordTMR, type, tooltip) {
_createToken(pixiTMR, linkData, coordTMR, code, tooltip) {
const token = {
sprite: this.createSprite(pixiTMR),
coordTMR: coordTMR,
tooltip: tooltip
tooltip: tooltip,
code: code ?? this.code()
};
token[type ?? this.code()] = linkData;
token[code ?? this.code()] = linkData;
return token;
}

View File

@@ -125,11 +125,11 @@ export class EffetsRencontre {
}
static experience_particuliere = async (dialog, context) => {
await context.actor.appliquerAjoutExperience(context)
await context.actor.ajoutExperience(context)
}
static regain_seuil = async (dialog, context) => {
await context.actor.regainPointDeSeuil()
await context.actor.recuperationSeuilReve()
}
static async $reinsertion(dialog, actor, filter) {

View File

@@ -8,7 +8,7 @@ items:
type: competencecreature
sort: 100000
flags: {}
img: systems/foundryvtt-reve-de-dragon/icons/competence_course.webp
img: systems/foundryvtt-reve-de-dragon/icons/creatures/glou_t.webp
effects: []
folder: null
system:
@@ -422,7 +422,7 @@ prototypeToken:
negative: false
priority: 0
texture:
src: icons/svg/mystery-man.svg
src: systems/foundryvtt-reve-de-dragon/icons/creatures/glou_t.webp
tint: '#ffffff'
scaleX: 1
scaleY: 1

View File

@@ -299,7 +299,7 @@ prototypeToken:
negative: false
priority: 0
texture:
src: systems/foundryvtt-reve-de-dragon/icons/creatures/sirene.svg
src: systems/foundryvtt-reve-de-dragon/icons/creatures/sirene_t.webp
tint: '#ffffff'
scaleX: 1
scaleY: 1

View File

@@ -348,7 +348,7 @@ prototypeToken:
negative: false
priority: 0
texture:
src: systems/foundryvtt-reve-de-dragon/icons/creatures/tigre-vert.svg
src: systems/foundryvtt-reve-de-dragon/icons/creatures/tigre-vert_t.webp
tint: '#ffffff'
scaleX: 1
scaleY: 1

View File

@@ -215,7 +215,7 @@ prototypeToken:
negative: false
priority: 0
texture:
src: systems/foundryvtt-reve-de-dragon/icons/creatures/chrasme_t.webp
src: systems/foundryvtt-reve-de-dragon/icons/creatures/chrasme_t-old.webp
tint: '#d53434'
scaleX: 0.8
scaleY: 0.8

View File

@@ -298,7 +298,7 @@ prototypeToken:
negative: false
priority: 0
texture:
src: systems/foundryvtt-reve-de-dragon/icons/creatures/zyglute.svg
src: systems/foundryvtt-reve-de-dragon/icons/creatures/zyglute_t.webp
tint: '#ffffff'
scaleX: 1
scaleY: 1

View File

@@ -7,7 +7,7 @@
"changelog": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md",
"compatibility": {
"minimum": "13",
"verified": "13"
"verified": "14"
},
"description": "Rêve de Dragon RPG for FoundryVTT",
"authors": [

View File

@@ -693,7 +693,9 @@
"bonus": 0
},
"localisation": "",
"origine": ""
"origine": "",
"vie": 0,
"endurance": "0"
},
"maladie": {
"templates": ["description", "temporel"],

View File

@@ -19,9 +19,11 @@
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/header-compteurs-creature.hbs"}}
<div class="flex-group-left header-etats">
<div class="flexcol">
<span>{{>"systems/foundryvtt-reve-de-dragon/templates/actor/header-effects.hbs"}}</span>
<span>{{system.compteurs.etat.label}}: {{system.compteurs.etat.value}}</span>
<span>{{calc.resumeBlessures}}</span>
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/header-effects.hbs"}}
{{#each calc.blessures as |blessure|}}
<span>{{blessure}}</span>
{{/each}}
</div>
</div>
</div>

View File

@@ -122,7 +122,7 @@
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/taches.hbs"}}
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/chirurgie.hbs"}}
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/oeuvres.hbs"}}
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/jeus.hbs"}}
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/jeux.hbs"}}
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/alchimie.hbs"}}
</div>
{{/if}}

View File

@@ -13,17 +13,17 @@
<li data-attribute="resistance" class="flexrow">
<span class="carac-label">Résistance</span>
<a class="resistance-moins"><i class="fa-solid fa-square-minus"></i></a>
<input type="text" name="system.etat.resistance.value" value="{{system.etat.resistance.value}}" data-dtype="Number" />
<input type="number" data-dtype="Number" name="system.etat.resistance.value" value="{{system.etat.resistance.value}}" min="0" max="{{system.etat.resistance.max}}"/>
/
<input type="text" name="system.etat.resistance.max" value="{{system.etat.resistance.max}}" data-dtype="Number" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
<input type="number" data-dtype="Number" name="system.etat.resistance.max" value="{{system.etat.resistance.max}}" min="0" {{#unless @root.options.vueDetaillee}}disabled{{/unless}}/>
<a class="resistance-plus"><i class="fa-solid fa-square-plus"></i></a>
</li>
<li data-attribute="structure" class="flexrow">
<span class="carac-label">Structure</span>
<a class="structure-moins"><i class="fa-solid fa-square-minus"></i></a>
<input type="text" name="system.etat.structure.value" value="{{system.etat.structure.value}}" data-dtype="Number" />
<input type="number" data-dtype="Number" name="system.etat.structure.value" value="{{system.etat.structure.value}}" min="0" max="{{system.etat.structure.max}}"/>
/
<input type="text" name="system.etat.structure.max" value="{{system.etat.structure.max}}" data-dtype="Number" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
<input type="number" data-dtype="Number" name="system.etat.structure.max" value="{{system.etat.structure.max}}" min="0" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
<a class="structure-plus"><i class="fa-solid fa-square-plus"></i></a>
</li>
</ul>
@@ -61,23 +61,23 @@
</li>
<li class="caracteristique flexrow list-item">
<span class="carac-label">Vitesse</span>
<input class="caracteristique streched" type="text" name="system.vitesse" value="{{system.vitesse}}" data-dtype="String" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
<input class="caracteristique streched" type="text" data-dtype="String" name="system.vitesse" value="{{system.vitesse}}" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
</li>
<li class="caracteristique flexrow list-item">
<span class="carac-label">Bonus rames</span>
<input class="caracteristique streched" type="text" name="system.bonus" value="{{system.bonus}}" data-dtype="String" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
<input class="caracteristique streched" type="text" data-dtype="String" name="system.bonus" value="{{system.bonus}}" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
</li>
<li class="caracteristique flexrow list-item">
<span class="carac-label">Manoeuvrabilité</span>
<input class="caracteristique streched" type="text" name="system.manoeuvrabilite" value="{{system.manoeuvrabilite}}" data-dtype="String" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
<input class="caracteristique streched" type="text" data-dtype="String" name="system.manoeuvrabilite" value="{{system.manoeuvrabilite}}" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
</li>
<li class="caracteristique flexrow list-item">
<span class="carac-label">Equipage</span>
<input class="caracteristique streched" type="text" name="system.equipage" value="{{system.equipage}}" data-dtype="Number" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
<input class="caracteristique streched" type="number" data-dtype="Number" name="system.equipage" value="{{system.equipage}}" min="0" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
</li>
<li class="caracteristique flexrow list-item">
<span class="carac-label">Capacité d'Encombrement</span>
<input class="caracteristique streched" type="text" name="system.capacite_encombrement" value="{{system.capacite_encombrement}}" data-dtype="Number" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
<input class="caracteristique streched" type="number" data-dtype="Number" name="system.capacite_encombrement" value="{{system.capacite_encombrement}}" min="0" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
</li>
</ol>
</div>

View File

@@ -16,10 +16,12 @@
{{#if (or options.isGM (gt system.attributs.protection.value 0))}}
<li class="caracteristique flexrow list-item">
<label for="system.attributs.protection.value" >Protection naturelle</label>
<input class="derivee-value" type="number" {{#unless options.isGM}}disabled{{/unless}} name="system.attributs.protection.value" value="{{system.attributs.protection.value}}" data-dtype="number"/>
<input name="system.attributs.protection.value" class="derivee-value" type="number" data-dtype="Number"
value="{{system.attributs.protection.value}}" min="0" max="20" {{#unless options.isGM}}disabled{{/unless}}
/>
</li>
{{/if}}
<li class="caracteristique flexrow list-item" >
<label class="derivee-label">Malus armure</label>
<input class="derivee-value" type="number" disabled value="{{calc.malusArmure}}" data-dtype="number"/>
<input class="derivee-value" type="number" data-dtype="Number" disabled value="{{calc.malusArmure}}" />
</li>

View File

@@ -1,18 +1,22 @@
<li class="item item-blessure flexrow list-item blessure-active-{{lowercase system.label}}" data-item-id="{{id}}"
data-tooltip="Blessure {{system.label}}">
<span class="blessure-control">
<span class="blessure-control flexrow">
<img class="sheet-competence-img" src="{{img}}" />
{{system.label}}
{{#if (gt system.gravite 0)}}
{{system.label}}
{{/if}}
</span>
{{#if (gt system.gravite 6)}}
<span class="flexrow"></span>
<span class="flexrow"></span>
<span class="flexrow"></span>
{{else}}
<span class="flexrow">
<input type="checkbox" class="blessure-premierssoins-done" name="blessure.{{id}}.premierssoins.done" {{#if system.premierssoins.done}}checked{{/if}}/>
<input name="blessure.{{id}}.premierssoins.done" type="checkbox" class="blessure-premierssoins-done" {{#if system.premierssoins.done}}checked{{/if}}/>
{{#if system.premierssoins.done}}
{{#unless system.soinscomplets.done}}
<input type="text" class="blessure-premierssoins-bonus number-x2" name="blessure.{{id}}.premierssoins.bonus" data-dtype="number" value="{{system.premierssoins.bonus}}"/>
<input name="blessure.{{id}}.premierssoins.bonus" type="text" data-dtype="Number" class="blessure-premierssoins-bonus number-x2"
value="{{system.premierssoins.bonus}}" min="-6" max="2"/>
{{/unless}}
{{else}}
<label>{{system.premierssoins.tache}} / {{system.gravite}}</label>
@@ -20,18 +24,22 @@
</span>
<span class="flexrow">
{{#if system.premierssoins.done}}
<input type="checkbox" class="blessure-soinscomplets-done" name="blessure.{{id}}.system.soinscomplets.done" {{#if system.soinscomplets.done}}checked{{/if}}/>
{{#if system.soinscomplets.done}}
<input type="text" class="blessure-soinscomplets-bonus number-x2" name="blessure.{{id}}.system.soinscomplets.bonus" data-dtype="number" value="{{system.soinscomplets.bonus}}"/>
{{/if}}
{{else}}
<label>Difficulté {{system.difficulte}}</label>
<input name="blessure.{{id}}.system.soinscomplets.done" type="checkbox" class="blessure-soinscomplets-done" {{#if system.soinscomplets.done}}checked{{/if}}/>
{{#if system.soinscomplets.done}}
<input name="blessure.{{id}}.system.soinscomplets.bonus" data-dtype="Number" type="text" class="blessure-soinscomplets-bonus number-x2"
value="{{system.soinscomplets.bonus}}" min="0" max="3"/>
{{/if}}
{{/if}}
</span>
<span class="flexrow">
{{#unless system.soinscomplets.done}}{{system.difficulte}}{{/unless}}
</span>
{{/if}}
<span>
{{#if system.origine}}<span>Par {{system.origine}}</span>{{/if}}
{{#if (regle-optionnelle 'localisation-aleatoire')}}
{{#if system.localisation}}<span>{{system.localisation}}</span>{{/if}}
{{/if}}
</span>
{{>'systems/foundryvtt-reve-de-dragon/templates/actor/item-action-controls.hbs' item=this options=@root.options}}
</li>

View File

@@ -13,10 +13,14 @@
<ul class="item-list alterne-list">
<li class="competence-header flexrow" >
<span></span>
<span>Premiers soins</span>
<span>Soins complets</span>
<span>Soins</span>
<span>premiers</span>
<span>complets</span>
<span>Diff</span>
<span>Source</span>
{{#if (regle-optionnelle 'localisation-aleatoire')}}
<span>Loc.</span>
{{/if}}
<span>Actions</span>
</li>
{{#each blessures as |blessure|}}

View File

@@ -28,51 +28,51 @@
<a class="flex-shrink moral-heureux" data-tooltip="Jet de moral situation heureuse"><i class="fa-regular fa-face-smile"></i></a>
</span>
</label>
<input class="derivee-value" type="number" name="system.compteurs.moral.value" value="{{system.compteurs.moral.value}}" data-dtype="number"/>
<input name="system.compteurs.moral.value" class="derivee-value" type="number" data-dtype="Number" value="{{system.compteurs.moral.value}}" min="-3" max="3"/>
</li>
<li class="caracteristique flexrow list-item">
<label>{{system.compteurs.exaltation.label}}</label>
<input class="derivee-value" type="number" name="system.compteurs.exaltation.value" value="{{system.compteurs.exaltation.value}}" data-dtype="number"/>
<input name="system.compteurs.exaltation.value" class="derivee-value" type="number" data-dtype="Number" value="{{system.compteurs.exaltation.value}}" min="0"/>
<label>{{system.compteurs.dissolution.label}}</label>
<input class="derivee-value" type="number" name="system.compteurs.dissolution.value" value="{{system.compteurs.dissolution.value}}" data-dtype="number"/>
<input name="system.compteurs.dissolution.value" class="derivee-value" type="number" data-dtype="Number" value="{{system.compteurs.dissolution.value}}" min="0"/>
</li>
<li class="caracteristique flexrow list-item">
<label class="derivee-label chance-actuelle" data-tooltip="Jet de chance actuelle"><a class="roll-chance-actuelle">Chance actuelle</a></label>
<input class="derivee-value" type="number" name="system.compteurs.chance.value" value="{{system.compteurs.chance.value}}" data-dtype="number"/>
<input name="system.compteurs.chance.value" class="derivee-value" type="number" data-dtype="Number" value="{{system.compteurs.chance.value}}" />
</li>
<li class="caracteristique flexrow list-item">
<label>Destinée</label>
<input class="derivee-value" type="number" name="system.compteurs.destinee.value" value="{{system.compteurs.destinee.value}}" data-dtype="number"/>
<input name="system.compteurs.destinee.value" class="derivee-value" type="number" data-dtype="Number" value="{{system.compteurs.destinee.value}}" min="0" max="7"/>
<label>voyage</label>
<input class="derivee-value" type="number" name="system.compteurs.voyage.value" value="{{system.compteurs.voyage.value}}" data-dtype="number"/>
<input name="system.compteurs.voyage.value" class="derivee-value" type="number" data-dtype="Number" value="{{system.compteurs.voyage.value}}" min="0" max="10"/>
</li>
<li class="caracteristique flexrow list-item">
<label class="flexrow derivee-label">{{system.compteurs.stress.label}}
<a class="stress-test" data-tooltip="Transformer le stress"><i class="fa-regular fa-moon"></i></a>
</label>
<input class="derivee-value" type="number" name="system.compteurs.stress.value" value="{{system.compteurs.stress.value}}" data-dtype="number"/>
<input name="system.compteurs.stress.value" class="derivee-value" type="number" data-dtype="Number" value="{{system.compteurs.stress.value}}" min=""/>
</li>
<br>
<li class="caracteristique flexrow list-item" data-tooltip="Niveau d'éthylisme">
<label for="system.compteurs.ethylisme.value">{{system.compteurs.ethylisme.label}}
{{#if system.compteurs.ethylisme.nb_doses}}({{system.compteurs.ethylisme.nb_doses}} doses){{/if}}
</label>
<select name="system.compteurs.ethylisme.value" class="derivee-value" data-dtype="Number">
{{selectOptions (RDD_CONFIG 'niveauEthylisme') selected=system.compteurs.ethylisme.value valueAttr="value" nameAttr="value" labelAttr="label"}}
</select>
</li>
<li class="caracteristique flexrow list-item">
<label>Sustentation</label>
<input class="derivee-value" type="number" disabled value="{{system.attributs.sust.value}}"/>
<input class="derivee-value" type="number" value="{{system.attributs.sust.value}}" disabled />
<label for="system.compteurs.sust.value">mangé</label>
<input class="derivee-value" type="number" name="system.compteurs.sust.value" value="{{system.compteurs.sust.value}}" data-dtype="number"/>
<input name="system.compteurs.sust.value" class="derivee-value" type="number" data-dtype="Number" value="{{system.compteurs.sust.value}}" />
</li>
<li class="caracteristique flexrow list-item">
<label></label>
<label></label>
<label for="system.compteurs.eau.value">bu</label>
<input class="derivee-value" type="number" name="system.compteurs.eau.value" value="{{system.compteurs.eau.value}}" data-dtype="number"/>
</li>
<li class="caracteristique flexrow list-item" data-tooltip="Niveau d'éthylisme">
<label for="system.compteurs.ethylisme.value">{{system.compteurs.ethylisme.label}}
{{#if system.compteurs.ethylisme.nb_doses}}({{system.compteurs.ethylisme.nb_doses}} doses){{/if}}
</label>
<select class="derivee-value" name="system.compteurs.ethylisme.value" data-dtype="Number">
{{selectOptions (RDD_CONFIG 'niveauEthylisme') selected=system.compteurs.ethylisme.value valueAttr="value" nameAttr="value" labelAttr="label"}}
</select>
<input name="system.compteurs.eau.value" class="derivee-value" type="number" data-dtype="Number" value="{{system.compteurs.eau.value}}" />
</li>
<br>
</ul>

View File

@@ -4,7 +4,9 @@
<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="carac.{{key}}" value="{{carac.value}}" data-dtype="number" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
<input name="carac.{{key}}" class="carac-value" type="number" data-dtype="Number"
value="{{carac.value}}" min="0" max="40"
{{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
<label class="carac-xp"/>
{{else}}
{{#if (actor-default @root.type 'carac' key 'derivee')}}
@@ -23,9 +25,12 @@
{{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="carac.{{key}}" value="{{carac.value}}" data-dtype="number" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
<input name="carac.{{key}}" class="carac-value" type="number" data-dtype="Number"
value="{{carac.value}}" min="0" max="40"
{{#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"
<input name="system.carac.{{key}}.xp" class="carac-xp" type="number" data-dtype="Number"
value="{{carac.xp}}" min="0" max="300"
data-tooltip="Vous devez acquérir {{carac.xpNext}} points d'Experience pour augmenter votre {{carac.label}}"
{{#unless @root.options.vueDetaillee}}disabled{{/unless}}
/>

View File

@@ -3,4 +3,10 @@
<span class="carac-label" name="carac-total">Total Caractéristiques</span>
<span class="competence-value" name="carac-total-value">{{calc.caracTotal}} </span>
</li>
{{#if @root.options.isGM}}
<li class="caracteristique flexrow">
<span class="carac-label" name="carac-total">Total XP Caractéristiques</span>
<span class="competence-value" name="carac-total-xp">{{calc.caracTotalXp}} </span>
</li>
{{/if}}
</ul>

View File

@@ -22,9 +22,9 @@
<div class="form-group">
<span>
<label for="system.pourcentage">Appliquer un pourcentage sur les prix</label>
<input {{@root.disabled}} class="attribute-value" type="number" data-dtype="Number"
name="system.pourcentage" value="{{system.pourcentage}}"
min="20" max="500" step="5"/>
<input name="system.pourcentage" class="attribute-value" type="number" data-dtype="Number"
value="{{system.pourcentage}}" min="20" max="500" step="5"
{{@root.disabled}} />
</span>
</div>
{{/if}}
@@ -40,13 +40,12 @@
</div>
<hr>
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire.hbs"}}
{{log @root.options}}
{{#unless system.illimite}}
{{#if @root.options.isObserver}}
<hr>
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-monnaie.hbs"}}
{{/if}}
{{/unless}}
<br>
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/editor-notes-mj.hbs"}}
<br>

View File

@@ -14,14 +14,14 @@
</a>
</span>
{{#unless item.parent.system.illimite}}
<span class="equipement-detail-buttons flexrow">
<span class="equipement-detail">
{{#unless (or (eq item.type 'service') (and (eq item.type 'conteneur') (not vide)))}}
{{#if options.isOwner}}
<a class="item-quantite-moins"><i class="fa-solid fa-square-minus"></i></a>
{{/if}}
<input {{#unless options.isOwner}}disabled{{/unless}} type="number" data-dtype="Number"
class="item-quantite number-x3" name="items[{{item._id}}].system.quantite"
value="{{item.system.quantite}}" />
<input name="items[{{item._id}}].system.quantite"
class="item-quantite number-x3" type="number" data-dtype="Number"
value="{{item.system.quantite}}" {{#unless options.isOwner}}disabled{{/unless}} />
{{#if options.isOwner}}
<a class="item-quantite-plus"><i class="fa-solid fa-square-plus"></i></a>
{{/if}}
@@ -30,13 +30,10 @@
{{/unless}}
<span class="equipement-detail">
{{#unless (and (eq item.type 'conteneur') (not vide))}}
<input {{#unless options.isOwner}}disabled{{/unless}} type="number" data-dtype="Number"
class="input-prix number-x3 item-cout" name="items[{{item._id}}].system.cout"
{{#if options.isObserver}}
value="{{numberFormat item.system.cout decimals=2 sign=false}}"
{{else}}
value="{{numberFormat (calculerPrixCommercant item) decimals=2 sign=false}}"
{{/if}} />
<input name="items[{{item._id}}].system.cout"
class="input-prix number-x3 item-cout" type="number" data-dtype="Number"
value="{{numberFormat (ifThen options.isObserver item.system.cout (calculerPrixCommercant item)) decimals=2 sign=false}}"
{{#unless options.isOwner}}disabled{{/unless}} />
{{/unless}}
</span>
{{>'systems/foundryvtt-reve-de-dragon/templates/actor/item-action-controls.hbs' item=item options=@root.options}}

View File

@@ -23,7 +23,7 @@
<span class="equipement-detail">Quantité</span>
{{/unless}}
<span class="equipement-detail">Prix (sols)</span>
<span class="equipement-actions">Actions</span>
<span class="item-actions-controls">Actions</span>
</li>
{{#each (trier inventaires) as |item id|}}
{{#unless item.estContenu}}

View File

@@ -8,15 +8,14 @@
<img class="sheet-competence-img" src="{{comp.img}}" data-tooltip="{{comp.name}}"/>
<span>{{comp.name}}</span>
</a>
<input class="competence-carac creature-carac" type="text" compname="{{comp.name}}" name="{{comp._id}}.carac"
value="{{comp.system.carac_value}}" data-dtype="number"
<input name="{{comp._id}}.carac" class="competence-carac creature-carac" type="number" data-dtype="Number"
compname="{{comp.name}}" value="{{comp.system.carac_value}}"
{{#unless @root.options.vueDetaillee}}disabled{{/unless}}/>
<input class="competence-value creature-niveau" type="text" data-dtype="number"
compname="{{comp.name}}" name="{{comp._id}}.niveau"
value="{{plusMoins comp.system.niveau}}"
<input name="{{comp._id}}.niveau" class="competence-value creature-niveau" type="text" data-dtype="Number"
compname="{{comp.name}}" value="{{plusMoins comp.system.niveau}}"
{{#unless @root.options.vueDetaillee}}disabled{{/unless}}
/>
<input class="competence-damage creature-dommages" type="text" data-dtype="number"
<input class="competence-damage creature-dommages" type="text" data-dtype="Number"
{{#if comp.isdommages}}
compname="{{comp.name}}" name="{{comp._id}}.dommages"
value="{{plusMoins comp.system.dommages}}"

View File

@@ -11,14 +11,14 @@
</a>
{{/if}}
<input class="competence-value" type="text" compname="{{name}}" name="comp-value-{{name}}"
value="{{plusMoins system.niveau}}" data-dtype="number"
{{#if (or (not @root.options.vueDetaillee) @root.options.vueArchetype)}}disabled{{/if}} />
<input name="comp-value-{{name}}" class="competence-value" type="text" data-dtype="Number"
compname="{{name}}" value="{{plusMoins system.niveau}}"
{{#if (or (not @root.options.vueDetaillee) @root.options.vueArchetype)}}disabled{{/if}} />
{{#if @root.options.vueDetaillee}}
<span class="competence-xp">
<input class="competence-xp " type="text" compname="{{name}}" name="comp-xp-{{name}}"
value="{{numberFormat system.xp decimals=0 sign=false}}" data-dtype="number"
<input name="comp-xp-{{name}}" class="competence-xp" type="text" data-dtype="Number"
compname="{{name}}" value="{{numberFormat system.xp decimals=0 sign=false}}"
{{#unless system.isLevelUp}}
data-tooltip="Vous devez acquérir {{system.xpNext}} points d'Experience pour augmenter de 1 votre compétence {{name}}"
{{/unless}}
@@ -26,8 +26,8 @@
</span>
{{/if}}
{{#if (eq system.categorie 'draconic')}}
<input class="competence-xp-sort" type="text" compname="{{name}}" name="comp-xp-sort-{{name}}"
value="{{numberFormat system.xp_sort decimals=0 sign=false}}" data-dtype="number"
<input name="comp-xp-sort-{{name}}" class="competence-xp-sort" type="text" data-dtype="Number"
compname="{{name}}" value="{{numberFormat system.xp_sort decimals=0 sign=false}}"
{{#if (or (not @root.options.vueDetaillee) @root.options.vueArchetype)}}disabled{{/if}} />
{{/if}}
{{#if @root.options.vueDetaillee}}
@@ -40,8 +40,9 @@
{{else}}
<i class="far fa-circle"></i>
{{/if}}
<input class="competence-archetype niveau-archetype" type="text" compname="{{name}}" name="comp-archetype-{{name}}"
value="{{plusMoins system.niveau_archetype}}" data-dtype="number" data-tooltip="Niveau d'archétype {{plusMoins system.niveau_archetype}}"
<input name="comp-archetype-{{name}}" class="competence-archetype niveau-archetype" type="text" data-dtype="Number"
compname="{{name}}" value="{{plusMoins system.niveau_archetype}}"
data-tooltip="Niveau d'archétype {{plusMoins system.niveau_archetype}}"
{{#if (not @root.options.vueArchetype)}}disabled{{/if}} />
</div>
{{>'systems/foundryvtt-reve-de-dragon/templates/actor/item-action-controls.hbs' item=this options=@root.options}}

View File

@@ -4,8 +4,9 @@
<label class="compteur">
<a class="jet-vie" name="system.sante.vie.label" data-tooltip="Faire un jet de vie">Vie</a>
<a class="vie-moins"><i class="fa-solid fa-square-minus"></i></a>
<input class="resource-content" type="text" name="system.sante.vie.value" value="{{system.sante.vie.value}}" data-dtype="Number" />
/ {{system.sante.vie.max}}
<input name="system.sante.vie.value" class="resource-content" type="number" data-dtype="Number"
value="{{system.sante.vie.value}}" min="0" max="{{system.sante.vie.max}}" />
/ {{system.sante.vie.max}}
<a class="vie-plus"><i class="fa-solid fa-square-plus"></i></a>
</label>
</li>
@@ -13,8 +14,9 @@
<label class="compteur">
<a class="jet-endurance" name="system.sante.endurance.label" data-tooltip="Faire un jet d'endurance pour ne pas être sonné">Endurance</a>
<a class="endurance-moins"><i class="fa-solid fa-square-minus"></i></a>
<input class="resource-content" type="text" name="system.sante.endurance.value" value="{{system.sante.endurance.value}}" data-dtype="Number"/>
/ {{system.sante.endurance.max}}
<input name="system.sante.endurance.value" class="resource-content" type="number" data-dtype="Number"
value="{{system.sante.endurance.value}}" min="0" max="{{system.sante.endurance.max}}" />
/ {{system.sante.endurance.max}}
<a class="endurance-plus"><i class="fa-solid fa-square-plus"></i></a>
</label>
</li>

View File

@@ -2,11 +2,12 @@
<div class="flex-group-center header-compteurs">
<ul>
<li data-attribute="endurance">
<label class="compteur">
<label class="compteur" for="system.sante.endurance.value">
Endurance
<a class="endurance-moins"><i class="fa-solid fa-square-minus"></i></a>
<input class="resource-content" type="text" name="system.sante.endurance.value" value="{{system.sante.endurance.value}}" data-dtype="Number" />
/ {{system.sante.endurance.max}}
<input name="system.sante.endurance.value" class="resource-content" type="text" data-dtype="Number"
value="{{system.sante.endurance.value}}" min="0" max="{{system.sante.endurance.max}}" />
/ {{system.sante.endurance.max}}
<a class="endurance-plus"><i class="fa-solid fa-square-plus"></i></a>
</label>
</li>

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