Compare commits

..

13 Commits
13.0.11 ... v13

Author SHA1 Message Date
e21f7e398a Création de tâches dans la fenêtre de jets 2025-10-18 00:52:14 +02:00
e16f89743a Affichage des ajustements V2 2025-10-18 00:52:14 +02:00
a6c593c100 Corrections premiers retours 2025-10-18 00:52:14 +02:00
cd8e190082 Merge pull request 'v13.0.12 - La méditation d'Illysis' (#776) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
All checks were successful
Release Creation / build (release) Successful in 1m49s
Reviewed-on: #776
2025-10-16 20:14:03 +02:00
f2106763c1 v13.0.12 2025-10-16 00:55:58 +02:00
5da5cb0314 Gestion des maladresses 2025-10-16 00:35:43 +02:00
6d7f66569a Lancer de sorts V2 2025-10-15 22:42:14 +02:00
3e8963b20b Impacts uniquement sur l'acteur 2025-10-15 22:42:14 +02:00
2cf5b06da8 Correction: rename bringToTop 2025-10-15 22:42:13 +02:00
68c01fc930 Montée TMR sur méditation
ajout d'un bouton pour aller dans les TMR lors d'une
méditation réussie
2025-10-15 22:42:13 +02:00
3bc1c4871b Biugfix: compétences de jeu
Les compétences de jeu spécifiques (doublon) ne remplacent plus
la compétence active si le jet n'est pas un jet de jeu
2025-10-15 00:26:01 +02:00
3d732e9a8a Suppression des signes draconiques
en cas de descente des TMR, suppression des signes
draconiques éphémères durant seulement 1 round
2025-10-15 00:24:35 +02:00
35f226af5c Correction du générateur aléatoire
- couleurs de cheveux/yeux
- les tailles entre 1m00 et 1m09 sont correctement affichées
- possibilité de positionner le sexe masculin/féminin en un clic
2025-10-14 17:44:39 +02:00
64 changed files with 861 additions and 365 deletions

1
assets/ui/maladresse.svg Normal file
View File

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

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,4 +1,29 @@
# 13.0 # 13.0
## 13.0.13 - L'épanouissement d'Illysis
- Fix d'erreur au chargement de templates RollDialog
- Nouvelle fenêtre de jets de dés
- Fix: affichage des points de tâche
- Fix: affichage des ajustements cohérent
- L'ouverture depuis les caractéristiques permet plusieurs types de jets
- On peut créer ou modifier les tâches dans la fenêtre de jets de tâches
- attaque/défense
- les maladresses sont affichées dans le résultat du jet
- le message au défenseur s'affiche correctement
- la difficulté d'attaque s'applique à la défense
- on peut choisir les particulières en rapidité
## 13.0.12 - La méditation d'Illysis
- les signes draconiques éphémères de 1 round sont supprimés à la descente des TMRs
- Générateur de description
- correction des termes pour les couleurs des yeux/cheveux
- ajout de boutons pour forcer le sexe masculin/féminin
- Nouvelle fenêtre de jets de dés
- les méditations proposent un bouton pour monter dans les TMRs
- fenêtre de lancer de sorts
- Correction: les compétences de jeux ne remplacent plus les compétences en dehors des jets de jeu
- gestion des maladresses d'attaque et défense
## 13.0.11 - Le gambit d'Illysis ## 13.0.11 - Le gambit d'Illysis

View File

@@ -707,6 +707,10 @@ select,
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-details div,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-details div {
display: block;
}
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions, .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-actions { .system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-actions {
grid-area: actions; grid-area: actions;
@@ -757,7 +761,10 @@ select,
.system-foundryvtt-reve-de-dragon .window-header { .system-foundryvtt-reve-de-dragon .window-header {
background: rgba(0, 0, 0, 0.75); background: rgba(0, 0, 0, 0.75);
} }
.system-foundryvtt-reve-de-dragon .application .window-content, .system-foundryvtt-reve-de-dragon .application .window-content {
margin: 0;
padding: 0.2rem;
}
.system-foundryvtt-reve-de-dragon .window-app.sheet .window-content { .system-foundryvtt-reve-de-dragon .window-app.sheet .window-content {
margin: 0.2rem; margin: 0.2rem;
padding: 0; padding: 0;
@@ -924,6 +931,12 @@ select,
.system-foundryvtt-reve-de-dragon a:hover { .system-foundryvtt-reve-de-dragon a:hover {
text-shadow: 1px 0px 0px #ff6600; text-shadow: 1px 0px 0px #ff6600;
} }
.system-foundryvtt-reve-de-dragon .tabs .item.active img,
.system-foundryvtt-reve-de-dragon .blessures-list li ul li:first-child:hover img,
.system-foundryvtt-reve-de-dragon i.moral-radio-checkmark-off:hover img,
.system-foundryvtt-reve-de-dragon a:hover img {
filter: drop-shadow(1px 0px 0px #ff6600);
}
.system-foundryvtt-reve-de-dragon .rollable:hover, .system-foundryvtt-reve-de-dragon .rollable:hover,
.system-foundryvtt-reve-de-dragon .rollable:focus { .system-foundryvtt-reve-de-dragon .rollable:focus {
color: #000; color: #000;
@@ -1448,12 +1461,27 @@ select,
.system-foundryvtt-reve-de-dragon .competence-list .item-controls.hidden-controls { .system-foundryvtt-reve-de-dragon .competence-list .item-controls.hidden-controls {
display: none !important; display: none !important;
} }
.system-foundryvtt-reve-de-dragon .item-actions-controls a.actionItem i:is(.fas, .fa, .fa-solid, .fa-regular), .system-foundryvtt-reve-de-dragon .item-actions-controls,
.system-foundryvtt-reve-de-dragon .item-controls {
vertical-align: super;
}
.system-foundryvtt-reve-de-dragon .item-actions-controls img,
.system-foundryvtt-reve-de-dragon .item-controls img {
display: inline;
max-width: 1rem;
max-height: 1rem;
margin: 0 0.1rem;
border: none;
filter: invert(0.8);
}
.system-foundryvtt-reve-de-dragon .item-actions-controls i:is(.fas, .fa, .fa-solid, .fa-regular),
.system-foundryvtt-reve-de-dragon .item-controls i:is(.fas, .fa, .fa-solid, .fa-regular) { .system-foundryvtt-reve-de-dragon .item-controls i:is(.fas, .fa, .fa-solid, .fa-regular) {
font-size: 0.8em; font-size: 0.8em;
color: var(--color-controls-light); color: var(--color-controls-light);
} }
.system-foundryvtt-reve-de-dragon .item-actions-controls a.actionItem i:is(.fas, .fa, .fa-solid, .fa-regular):hover, .system-foundryvtt-reve-de-dragon .item-actions-controls img:hover,
.system-foundryvtt-reve-de-dragon .item-controls img:hover,
.system-foundryvtt-reve-de-dragon .item-actions-controls i:is(.fas, .far, .fa-solid, .fa-regular):hover,
.system-foundryvtt-reve-de-dragon .item-controls i:is(.fas, .far, .fa-solid, .fa-regular):hover { .system-foundryvtt-reve-de-dragon .item-controls i:is(.fas, .far, .fa-solid, .fa-regular):hover {
opacity: 0.6; opacity: 0.6;
} }
@@ -1596,6 +1624,9 @@ select,
color: var(--color-text-dark-primary); color: var(--color-text-dark-primary);
border-radius: 0.2rem; border-radius: 0.2rem;
} }
.system-foundryvtt-reve-de-dragon form.app-personnage-aleatoire h2 {
min-width: 30rem;
}
.system-foundryvtt-reve-de-dragon .app-calendar-astrologie div.theme-astral { .system-foundryvtt-reve-de-dragon .app-calendar-astrologie div.theme-astral {
width: 14rem; width: 14rem;
margin: 0.4rem; margin: 0.4rem;
@@ -1616,8 +1647,9 @@ select,
height: 2rem; height: 2rem;
} }
.system-foundryvtt-reve-de-dragon .window-app .window-content, .system-foundryvtt-reve-de-dragon .window-app .window-content,
.system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-body { .system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-body,
background: #f5f5f0 url(../assets/ui/bg_left.webp) no-repeat left top; .system-foundryvtt-reve-de-dragon .application .window-content {
background: url(../assets/ui/bg_left.webp) no-repeat left top;
} }
.system-foundryvtt-reve-de-dragon section.sheet-body { .system-foundryvtt-reve-de-dragon section.sheet-body {
padding: 0.25rem 0.5rem; padding: 0.25rem 0.5rem;
@@ -2292,7 +2324,7 @@ select,
pointer-events: all; pointer-events: all;
} }
.system-foundryvtt-reve-de-dragon div.horloge-roue div.horloge-cercle { .system-foundryvtt-reve-de-dragon div.horloge-roue div.horloge-cercle {
background: hsl(60, 20%, 95%) url(../assets/ui/bg_left.webp) no-repeat left top; background: hsla(60, 20%, 90%, 0.8);
top: 2%; top: 2%;
left: 2%; left: 2%;
width: 96%; width: 96%;
@@ -2737,11 +2769,9 @@ select,
} }
.system-foundryvtt-reve-de-dragon .chat-card-button:hover { .system-foundryvtt-reve-de-dragon .chat-card-button:hover {
background: var(--background-custom-button-hover); background: var(--background-custom-button-hover);
background-color: red;
} }
.system-foundryvtt-reve-de-dragon .chat-card-button-pushed:hover { .system-foundryvtt-reve-de-dragon .chat-card-button-pushed:hover {
background: var(--background-custom-button-hover); background: var(--background-custom-button-hover);
background-color: red;
} }
.system-foundryvtt-reve-de-dragon .chat-card-button:active, .system-foundryvtt-reve-de-dragon .chat-card-button:active,
.system-foundryvtt-reve-de-dragon .chat-card-button-pushed:active { .system-foundryvtt-reve-de-dragon .chat-card-button-pushed:active {

View File

@@ -12,7 +12,10 @@
background: rgba(0,0,0,0.75); background: rgba(0,0,0,0.75);
} }
.application .window-content, .application .window-content {
margin: 0;
padding: 0.2rem;
}
.window-app.sheet .window-content { .window-app.sheet .window-content {
margin: 0.2rem; margin: 0.2rem;
padding: 0; padding: 0;
@@ -200,6 +203,9 @@
i.moral-radio-checkmark-off:hover, i.moral-radio-checkmark-off:hover,
a:hover { a:hover {
text-shadow: 1px 0px 0px #ff6600; text-shadow: 1px 0px 0px #ff6600;
img {
filter: drop-shadow(1px 0px 0px #ff6600);
}
} }
.rollable:hover, .rollable:focus { .rollable:hover, .rollable:focus {
@@ -754,15 +760,30 @@
.competence-list .item-controls.hidden-controls { .competence-list .item-controls.hidden-controls {
display: none !important; display: none !important;
} }
.item-actions-controls,
.item-controls {
vertical-align: super;
// a {
// }
.item-actions-controls a.actionItem i:is(.fas, .fa, .fa-solid, .fa-regular), img {
.item-controls i:is(.fas, .fa, .fa-solid, .fa-regular) { display: inline;
font-size: 0.8em; max-width: 1rem;
color: var(--color-controls-light); max-height: 1rem;
} margin: 0 0.1rem;
.item-actions-controls a.actionItem i:is(.fas, .fa, .fa-solid, .fa-regular):hover, border: none;
.item-controls i:is(.fas, .far, .fa-solid, .fa-regular):hover { filter: invert(0.8);
opacity: 0.6; }
i:is(.fas, .fa, .fa-solid, .fa-regular) {
font-size: 0.8em;
color: var(--color-controls-light);
}
img:hover,
i:is(.fas, .far, .fa-solid, .fa-regular):hover {
opacity: 0.6;
}
} }
.rdd-roll-dialog .description-sort { .rdd-roll-dialog .description-sort {
@@ -910,6 +931,11 @@
color: var(--color-text-dark-primary); color: var(--color-text-dark-primary);
border-radius: 0.2rem; border-radius: 0.2rem;
} }
form.app-personnage-aleatoire {
h2 {
min-width: 30rem,
}
}
.app-calendar-astrologie{ .app-calendar-astrologie{
div.theme-astral{ div.theme-astral{
width: 14rem; width: 14rem;
@@ -932,8 +958,10 @@
} }
} }
.window-app .window-content, .window-app.sheet .window-content .sheet-body{ .window-app .window-content,
background: rgb(245,245,240) url(../assets/ui/bg_left.webp) no-repeat left top; .window-app.sheet .window-content .sheet-body,
.application .window-content {
background: url(../assets/ui/bg_left.webp) no-repeat left top;
} }
section.sheet-body { section.sheet-body {
@@ -1654,7 +1682,7 @@
} }
div.horloge-roue div.horloge-cercle { div.horloge-roue div.horloge-cercle {
background: hsl(60, 20%, 95%) url(../assets/ui/bg_left.webp) no-repeat left top; background: hsla(60, 20%, 90%, 0.8);
top: 2%; left: 2%; width: 96%; height: 96%; border-radius: 50%; top: 2%; left: 2%; width: 96%; height: 96%; border-radius: 50%;
} }
@@ -1998,12 +2026,10 @@
.chat-card-button:hover { .chat-card-button:hover {
background: var(--background-custom-button-hover); background: var(--background-custom-button-hover);
background-color: red;
} }
.chat-card-button-pushed:hover { .chat-card-button-pushed:hover {
background: var(--background-custom-button-hover); background: var(--background-custom-button-hover);
background-color: red;
} }
.chat-card-button:active, .chat-card-button-pushed:active { .chat-card-button:active, .chat-card-button-pushed:active {

View File

@@ -37,6 +37,9 @@
text-align: justify; text-align: justify;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
div {
display: block;
}
} }
div.chat-actions { div.chat-actions {
grid-area: actions; grid-area: actions;

View File

@@ -342,7 +342,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
/* -------------------------------------------- */ /* -------------------------------------------- */
async createEmptyTache() { async createEmptyTache() {
await this.actor.createItem('tache', 'Nouvelle tache'); await this.actor.createItem(ITEM_TYPES.tache, 'Nouvelle tache')
} }
_getActionCombat(event) { _getActionCombat(event) {

View File

@@ -47,11 +47,12 @@ import { RdDRollResult } from "./rdd-roll-result.js";
import { RdDInitiative } from "./initiative.mjs"; import { RdDInitiative } from "./initiative.mjs";
import RollDialog from "./roll/roll-dialog.mjs"; import RollDialog from "./roll/roll-dialog.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js"; import { OptionsAvancees, ROLL_DIALOG_V2, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js";
import { ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION } from "./roll/roll-constants.mjs"; import { ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_SORT } from "./roll/roll-constants.mjs";
import { PART_TACHE } from "./roll/roll-part-tache.mjs"; import { PART_TACHE } from "./roll/roll-part-tache.mjs";
import { PART_COMP } from "./roll/roll-part-comp.mjs"; import { PART_COMP } from "./roll/roll-part-comp.mjs";
import { PART_OEUVRE } from "./roll/roll-part-oeuvre.mjs"; import { PART_OEUVRE } from "./roll/roll-part-oeuvre.mjs";
import { PART_CUISINE } from "./roll/roll-part-cuisine.mjs"; import { PART_CUISINE } from "./roll/roll-part-cuisine.mjs";
import { PART_SORT } from "./roll/roll-part-sort.mjs";
export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre'] export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre']
@@ -741,12 +742,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async sortMisEnReserve(sort, draconic, coord, ptreve) { async sortMisEnReserve(sort, draconic, coord, ptreve) {
await this.createEmbeddedDocuments("Item", [{ await this.createEmbeddedDocuments("Item", [RdDItemSort.prepareSortEnReserve(sort, draconic, ptreve, coord)],
type: ITEM_TYPES.sortreserve,
name: sort.name,
img: sort.img,
system: { sortid: sort._id, draconic: (draconic?.name ?? sort.system.draconic), ptreve: ptreve, coord: coord, heurecible: 'Vaisseau' }
}],
{ renderSheet: false }); { renderSheet: false });
this.tmrApp.updateTokens(); this.tmrApp.updateTokens();
} }
@@ -1712,15 +1708,18 @@ export class RdDActor extends RdDBaseActorSang {
ui.notifications.error("Une queue ou un souffle vous empèche de lancer de sort!") ui.notifications.error("Une queue ou un souffle vous empèche de lancer de sort!")
return return
} }
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
return await this.rollUnSortV2();
}
// Duplication car les pts de reve sont modifiés dans le sort! // Duplication car les pts de reve sont modifiés dans le sort!
let sorts = foundry.utils.duplicate(this.itemTypes[ITEM_TYPES.sort].filter(it => RdDItemSort.isSortOnCoord(it, coord))) let sorts = foundry.utils.duplicate(this.itemTypes[ITEM_TYPES.sort].filter(it => RdDItemSort.isSortOnCoord(it, coord)))
if (sorts.length == 0) { if (sorts.length == 0) {
ui.notifications.info(`Aucun sort disponible en ${TMRUtility.getTMR(coord).label} !`); ui.notifications.info(`Aucun sort disponible en ${TMRUtility.getTMR(coord).label} !`);
return; return
} }
const draconicList = this.computeDraconicAndSortIndex(sorts); const draconicList = this.computeDraconicAndSortIndex(sorts)
const reve = foundry.utils.duplicate(this.system.carac.reve); const reve = foundry.utils.duplicate(this.system.carac.reve)
const dialog = await this.openRollDialog({ const dialog = await this.openRollDialog({
name: 'lancer-un-sort', name: 'lancer-un-sort',
@@ -1743,6 +1742,27 @@ export class RdDActor extends RdDBaseActorSang {
this.tmrApp?.setTMRPendingAction(dialog); this.tmrApp?.setTMRPendingAction(dialog);
} }
async rollUnSortV2() {
const rollData = {
ids: { actorId: this.id },
type: { allowed: [ROLL_TYPE_SORT], current: ROLL_TYPE_SORT }
};
const dialog = await RollDialog.create(rollData, {
callbacks: [roll => {
this.tmrApp?.restoreTMRAfterAction();
if (roll.closeTMR) {
this.tmrApp?.close();
this.tmrApp = undefined;
}
} ],
onRollDone: RollDialog.onRollDoneClose,
onClose: () => {
this.tmrApp?.restoreTMRAfterAction();
}
});
this.tmrApp?.setTMRPendingAction(dialog);
}
/* -------------------------------------------- */ /* -------------------------------------------- */
isMauvaiseRencontre() { // Gestion queue/souffle 'Mauvaise Rencontre en Perpective' isMauvaiseRencontre() { // Gestion queue/souffle 'Mauvaise Rencontre en Perpective'
let addMsg = ""; let addMsg = "";
@@ -1814,11 +1834,7 @@ export class RdDActor extends RdDBaseActorSang {
} }
else { else {
console.log('lancement de sort', rollData.selectedSort) console.log('lancement de sort', rollData.selectedSort)
const precedents = rollData.selectedSort.system.lancements ?? [] const lancements = RdDItemSort.prepareSortAddLancement(rollData.selectedSort, rollData.selectedSort.system.ptreve_reel)
const lancements = [...precedents, {
timestamp: game.system.rdd.calendrier.getTimestamp(),
reve: rollData.selectedSort.system.ptreve_reel
}]
await this.updateEmbeddedDocuments('Item', await this.updateEmbeddedDocuments('Item',
[{ _id: rollData.selectedSort._id, 'system.lancements': lancements }] [{ _id: rollData.selectedSort._id, 'system.lancements': lancements }]
) )
@@ -2109,7 +2125,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
_getSignesDraconiques(coord) { _getSignesDraconiques(coord) {
const type = TMRUtility.getTMRType(coord); const type = TMRUtility.getTMRType(coord);
return this.itemTypes["signedraconique"].filter(it => it.system.typesTMR.includes(type)); return this.itemTypes[ITEM_TYPES.signedraconique].filter(it => it.system.typesTMR.includes(type));
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -2121,18 +2137,19 @@ export class RdDActor extends RdDBaseActorSang {
async rollLireSigneDraconique(coord) { async rollLireSigneDraconique(coord) {
if (!this.isHautRevant()) { if (!this.isHautRevant()) {
ui.notifications.info("Seul un haut rêvant peut lire un signe draconique!"); ui.notifications.info("Seul un haut rêvant peut lire un signe draconique!");
return; return
} }
let signes = this._getSignesDraconiques(coord); let signes = this._getSignesDraconiques(coord)
if (signes.length == 0) { if (signes.length == 0) {
ui.notifications.info(`Aucun signe draconiques en ${coord} !`); ui.notifications.info(`Aucun signe draconiques en ${coord} !`)
return; return
} }
let draconicList = this.getDraconics() let draconicList = this.getDraconics()
.map(draconic => { .map(draconic => {
let draconicLecture = foundry.utils.duplicate(draconic); let draconicLecture = foundry.utils.duplicate(draconic)
draconicLecture.system.defaut_carac = "intellect"; draconicLecture.system.defaut_carac = "intellect"
return draconicLecture; return draconicLecture
}); });
const intellect = this.system.carac.intellect; const intellect = this.system.carac.intellect;
@@ -2406,7 +2423,7 @@ export class RdDActor extends RdDBaseActorSang {
if (this.tmrApp) { if (this.tmrApp) {
ui.notifications.warn("Vous êtes déja dans les TMR....") ui.notifications.warn("Vous êtes déja dans les TMR....")
this.tmrApp.forceTMRDisplay() this.tmrApp.forceTMRDisplay()
return return false
} }
if (mode != 'visu' && this.isDemiReve()) { if (mode != 'visu' && this.isDemiReve()) {
ui.notifications.warn("Le personnage est déjà dans les Terres Médianes, elles s'affichent en visualisation") ui.notifications.warn("Le personnage est déjà dans les Terres Médianes, elles s'affichent en visualisation")
@@ -2414,6 +2431,7 @@ export class RdDActor extends RdDBaseActorSang {
} }
if (mode == 'visu') { if (mode == 'visu') {
await this._doDisplayTMR(mode) await this._doDisplayTMR(mode)
return false
} }
else { else {
const rencontre = this.getRencontreTMREnAttente(); const rencontre = this.getRencontreTMREnAttente();
@@ -2426,6 +2444,7 @@ export class RdDActor extends RdDBaseActorSang {
buttonLabel: 'Monter dans les TMR', buttonLabel: 'Monter dans les TMR',
onAction: async () => await this._doDisplayTMR(mode) onAction: async () => await this._doDisplayTMR(mode)
}) })
return true
} }
} }
@@ -2463,6 +2482,29 @@ export class RdDActor extends RdDBaseActorSang {
await this.tmrApp.onDeplacement() await this.tmrApp.onDeplacement()
} }
async quitterTMR(message, viewOnly, cumulFatigue) {
if (this.tmrApp) {
this.tmrApp = undefined
const appliquerFatigue = ReglesOptionnelles.isUsing("appliquer-fatigue");
await this.santeIncDec(
appliquerFatigue ? "fatigue" : "endurance",
(appliquerFatigue ? 1 : -1) * cumulFatigue)
if (!viewOnly) {
await this.supprimerSignesDraconiques(it => it.system.ephemere && it.system.duree == '1 round', { render: false })
await this.setEffect(STATUSES.StatusDemiReve, false)
ChatUtility.tellToUserAndGM(message)
}
}
}
async supprimerSignesDraconiques(filter = it => true, options = { render: true }) {
const signes = this.itemTypes[ITEM_TYPES.signedraconique].filter(filter)
if (signes.length > 0) {
this.deleteEmbeddedDocuments("Item", signes.map(item => item.id), options)
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollSoins(blesse, blessureId) { async rollSoins(blesse, blessureId) {
const blessure = blesse.blessuresASoigner().find(it => it.id == blessureId); const blessure = blesse.blessuresASoigner().find(it => it.id == blessureId);

View File

@@ -246,10 +246,10 @@ export class RdDBaseActorReve extends RdDBaseActor {
if (this.isEffectAllowed(statusId)) { if (this.isEffectAllowed(statusId)) {
const effect = this.getEffectByStatus(statusId); const effect = this.getEffectByStatus(statusId);
if (!status && effect) { if (!status && effect) {
await this.deleteEmbeddedDocuments('ActiveEffect', [effect.id]); await this.deleteEmbeddedDocuments('ActiveEffect', [effect.id], { render: true})
} }
if (status && !effect) { if (status && !effect) {
await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(statusId)]); await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(statusId)], { render: true})
} }
} }
} }
@@ -387,7 +387,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) { if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = { const rollData = {
ids: { actorId: this.id }, ids: { actorId: this.id },
type: { allowed: [PART_COMP], current: PART_COMP }, type: { allowed: DEFAULT_ROLL_TYPES, current: PART_COMP },
selected: { selected: {
carac: { key: caracName }, carac: { key: caracName },
comp: options.resistance ? { key: undefined, forced: true } : undefined comp: options.resistance ? { key: undefined, forced: true } : undefined

View File

@@ -116,6 +116,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
blessure: blessure blessure: blessure
}); });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async santeIncDec(name, inc, isCritique = false) { async santeIncDec(name, inc, isCritique = false) {
if (name == 'fatigue' && !ReglesOptionnelles.isUsing("appliquer-fatigue")) { if (name == 'fatigue' && !ReglesOptionnelles.isUsing("appliquer-fatigue")) {
@@ -179,6 +180,26 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
return Math.max(0, Math.min(maxEndVie, maxEndGraves, maxEndCritiques)); return Math.max(0, Math.min(maxEndVie, maxEndGraves, maxEndCritiques));
} }
async onCreateItem(item, options, id) {
switch (item.type) {
case ITEM_TYPES.blessure:
await this.changeBleedingState()
break
}
}
async onUpdateItem(item, options, id) {
switch (item.type) {
case ITEM_TYPES.blessure:
await this.changeBleedingState()
break
}
}
async changeBleedingState() {
const bleeding = this.itemTypes[ITEM_TYPES.blessure].find(it => it.isBleeding())
await this.setEffect(STATUSES.StatusBleeding, bleeding ? true : false)
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async ajouterBlessure(encaissement, attackerToken = undefined) { async ajouterBlessure(encaissement, attackerToken = undefined) {

View File

@@ -248,28 +248,12 @@ export class RdDBaseActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async onPreUpdateItem(item, change, options, id) { } async onPreUpdateItem(item, change, options, id) { }
async onCreateItem(item, options, id) { async onCreateItem(item, options, id) { }
switch (item.type) {
case ITEM_TYPES.blessure:
await this.changeBleedingState()
break
}
}
async onUpdateItem(item, options, id) { async onUpdateItem(item, options, id) { }
switch (item.type) {
case ITEM_TYPES.blessure:
await this.changeBleedingState()
break
}
}
async changeBleedingState() {
const bleeding = this.itemTypes[ITEM_TYPES.blessure].find(it => it.isBleeding())
await this.setEffect(STATUSES.StatusBleeding, bleeding ? true : false)
}
async onUpdateActor(update, options, actorId) { } async onUpdateActor(update, options, actorId) { }
async onDeleteItem(item, options, id) { async onDeleteItem(item, options, id) {
if (item.isInventaire()) { if (item.isInventaire()) {
await this._removeItemFromConteneur(item) await this._removeItemFromConteneur(item)

View File

@@ -20,14 +20,15 @@ const PATHS = [
const RANDOM_VALUES = { const RANDOM_VALUES = {
'system.sexe': { 'masculin': 1, 'féminin': 1 }, 'system.sexe': { 'masculin': 1, 'féminin': 1 },
'system.main': { 'droitier': 51, 'gaucher': 15, 'ambidextre': 6 }, 'system.main': { 'droitier': 51, 'gaucher': 15, 'ambidextre': 6 },
'system.cheveux': { 'noirs': 2, 'bruns': 5, 'châtains clair': 5, 'blonds': 4, 'blonds très clair': 1, 'roux carotte': 1, 'roux cuivré': 3 }, 'system.cheveux': { 'noirs': 2, 'bruns': 5, 'châtains': 3, 'châtain clair': 5, 'blonds': 4, 'blond platine': 1, 'roux carotte': 1, 'roux cuivré': 3, 'chauve': 1 },
'system.yeux': { 'noirs': 2, 'noisettes': 3, 'bruns vert': 4, 'verts': 3, 'bleus clair': 3, 'bleus gris': 2, 'gris': 1, 'mauves': 1, 'indigos': 1 }, 'system.yeux': { 'noirs': 2, 'noisette': 3, 'brun vert': 4, 'verts': 3, 'bleu clair': 3, 'bleu gris': 2, 'gris': 1, 'mauves': 1, 'indigos': 1 },
} }
export class AppPersonnageAleatoire extends FormApplication { export class AppPersonnageAleatoire extends FormApplication {
static preloadHandlebars() { static preloadHandlebars() {
foundry.applications.handlebars.loadTemplates([ foundry.applications.handlebars.loadTemplates([
'systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs', 'systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/random/sexe-aleatoire.hbs',
]) ])
} }
@@ -49,14 +50,14 @@ export class AppPersonnageAleatoire extends FormApplication {
this.current = foundry.utils.duplicate(actor) this.current = foundry.utils.duplicate(actor)
this.checked = { this.checked = {
'name': false, 'name': false,
'system.sexe': true, 'system.sexe': (this.actor.system.sexe ?? '') == '',
'system.age': true, 'system.age': this.actor.system.age == 0,
'system.taille': true, 'system.taille': (this.actor.system.taille ?? '') == '',
'system.poids': true, 'system.poids': (this.actor.system.poids ?? '') == '',
'system.main': true, 'system.main': (this.actor.system.main ?? '') == '',
'system.heure': true, 'system.heure': (this.actor.system.heure ?? '') == '',
'system.cheveux': true, 'system.cheveux': (this.actor.system.cheveux ?? '') == '',
'system.yeux': true 'system.yeux': (this.actor.system.yeux ?? '') == '',
} }
} }
@@ -76,6 +77,8 @@ export class AppPersonnageAleatoire extends FormApplication {
this.html.find("button.button-apply").click(async event => await this.onApply()) this.html.find("button.button-apply").click(async event => await this.onApply())
this.html.find("input.current-value").change(async event => await this.onChange(event)) this.html.find("input.current-value").change(async event => await this.onChange(event))
this.html.find("div.random-field[data-path='system.heure'] select.current-value").change(async event => await this.onChange(event)) this.html.find("div.random-field[data-path='system.heure'] select.current-value").change(async event => await this.onChange(event))
this.html.find('a[data-action="sexe-masculin"]').click(async event => await this.onSexe('masculin'))
this.html.find('a[data-action="sexe-feminin"]').click(async event => await this.onSexe('féminin'))
this.html.find("a.random").click(async event => await this.onRandom(event)) this.html.find("a.random").click(async event => await this.onRandom(event))
this.html.find("a.reset").click(async event => await this.onReset(event)) this.html.find("a.reset").click(async event => await this.onReset(event))
this.html.find("a.randomize-selected").click(async event => await this.onRandomizeSelected()) this.html.find("a.randomize-selected").click(async event => await this.onRandomizeSelected())
@@ -96,6 +99,10 @@ export class AppPersonnageAleatoire extends FormApplication {
const fields = this.html.find(selector).parents("div.random-field:first") const fields = this.html.find(selector).parents("div.random-field:first")
return fields[0].attributes['data-path'].value return fields[0].attributes['data-path'].value
} }
async onSexe(sexe) {
this.current['system.sexe'] = sexe
this.render()
}
async onChange(event) { async onChange(event) {
const path = this.getPath(event.currentTarget) const path = this.getPath(event.currentTarget)
@@ -180,8 +187,9 @@ export class AppPersonnageAleatoire extends FormApplication {
const variation = Math.floor((caracTaille.poidsMax - caracTaille.poidsMin + base / 5) / 2) const variation = Math.floor((caracTaille.poidsMax - caracTaille.poidsMin + base / 5) / 2)
const total = await RdDDice.rollTotal(`2d${variation} + ${base}`) const total = await RdDDice.rollTotal(`2d${variation} + ${base}`)
const cm = total % 100 const cm = total % 100
const dm = cm < 10 ? '0' : ''
const m = (total - cm) / 100 const m = (total - cm) / 100
return `${m}m${cm}` return `${m}m${dm}${cm}`
} }

View File

@@ -106,6 +106,25 @@ export class ChatUtility {
return await ChatMessage.create(messageData) return await ChatMessage.create(messageData)
} }
static tellToUser(message) {
ChatMessage.create({ content: message, user: game.user.id, whisper: [game.user.id] });
}
static tellToGM(message) {
ChatMessage.create({
user: game.user.id,
content: message,
whisper: ChatUtility.getGMs()
});
}
static tellToUserAndGM(message) {
ChatMessage.create({
user: game.user.id,
content: message,
whisper: ChatUtility.getUserAndGMs()
})
}
static getOwners(document) { static getOwners(document) {
return document ? game.users.filter(it => document.getUserLevel(it) == CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) : [game.user] return document ? game.users.filter(it => document.getUserLevel(it) == CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) : [game.user]
} }

View File

@@ -55,7 +55,7 @@ export const RDD_CONFIG = {
particuliere: { particuliere: {
force: { key: 'force', descr: 'en force', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-force.svg'}, force: { key: 'force', descr: 'en force', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-force.svg'},
finesse: { key: 'finesse', descr: 'en finesse', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-finesse.svg'}, finesse: { key: 'finesse', descr: 'en finesse', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-finesse.svg'},
rapidite: { key: 'finesse', descr: 'en rapidité', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-rapidite.svg'}, rapidite: { key: 'rapidite', descr: 'en rapidité', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-rapidite.svg'},
} }
} }

View File

@@ -148,10 +148,17 @@ export class RdDItemSort extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static incrementBonusCase(actor, sort, coord) { static incrementBonusCase(actor, sort, coord) {
let bonuscase = RdDItemSort.calculBonuscase(sort, coord)
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': bonuscase }]);
}
static calculBonuscase(sort, coord) {
if (TMRUtility.isFleuve(coord)) { if (TMRUtility.isFleuve(coord)) {
coord = FLEUVE_COORD; coord = FLEUVE_COORD
} }
let list = RdDItemSort.stringToBonuscases(sort.system.bonuscase); let list = RdDItemSort.stringToBonuscases(sort.system.bonuscase)
const existing = list.find(it => it.case == coord) const existing = list.find(it => it.case == coord)
const bonus = Number(existing?.bonus ?? 0) + 1 const bonus = Number(existing?.bonus ?? 0) + 1
if (existing) { if (existing) {
@@ -160,11 +167,9 @@ export class RdDItemSort extends Item {
else { else {
list.push({ case: coord, bonus: 1 }) list.push({ case: coord, bonus: 1 })
} }
return RdDItemSort.bonuscasesToString(list)
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': RdDItemSort.bonuscasesToString(list) }]);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getCaseBonus(sort, coord) { static getCaseBonus(sort, coord) {
const search = TMRUtility.isFleuve(coord) const search = TMRUtility.isFleuve(coord)
@@ -189,4 +194,22 @@ export class RdDItemSort extends Item {
.map(it => it.split(':')) .map(it => it.split(':'))
.map(it => { return { case: it[0], bonus: it[1] } }); .map(it => { return { case: it[0], bonus: it[1] } });
} }
static prepareSortEnReserve(sort, draconic, ptreve, coord) {
return {
type: ITEM_TYPES.sortreserve,
name: sort.name,
img: sort.img,
system: { sortid: sort._id, draconic: (draconic?.name ?? sort.system.draconic), ptreve: ptreve, coord: coord, heurecible: 'Vaisseau' }
};
}
static prepareSortAddLancement(sort, reveSort) {
const precedents = sort.system.lancements ?? []
const lancements = [...precedents, {
timestamp: game.system.rdd.calendrier.getTimestamp(),
reve: reveSort
}]
return lancements
}
} }

View File

@@ -47,7 +47,7 @@ export class RdDBonus {
penetration: RdDBonus._peneration(rollData), penetration: RdDBonus._peneration(rollData),
dmgTactique: RdDBonus.dmgBonus(rollData.tactique), dmgTactique: RdDBonus.dmgBonus(rollData.tactique),
dmgParticuliere: RdDBonus._dmgParticuliere(rollData), dmgParticuliere: RdDBonus._dmgParticuliere(rollData),
dmgSurprise: RdDBonus.dmgBonus(rollData.ajustements?.attaqueDefenseurSurpris.used), dmgSurprise: RdDBonus.dmgBonus(rollData.ajustements?.attaqueDefenseurSurpris?.used),
mortalite: RdDBonus._calculMortalite(rollData, isEntiteIncarnee), mortalite: RdDBonus._calculMortalite(rollData, isEntiteIncarnee),
dmgActor: RdDBonus.bonusDmg(actor, rollData.selectedCarac?.label.toLowerCase(), dmgArme), dmgActor: RdDBonus.bonusDmg(actor, rollData.selectedCarac?.label.toLowerCase(), dmgArme),
dmgForceInsuffisante: Math.min(0, actor.getForce() - forceRequise) dmgForceInsuffisante: Math.min(0, actor.getForce() - forceRequise)

View File

@@ -15,9 +15,8 @@ import { RdDItemCompetence } from "./item-competence.js";
import { MAP_PHASE, RdDInitiative } from "./initiative.mjs"; import { MAP_PHASE, RdDInitiative } from "./initiative.mjs";
import RollDialog from "./roll/roll-dialog.mjs"; import RollDialog from "./roll/roll-dialog.mjs";
import { PART_DEFENSE } from "./roll/roll-part-defense.mjs"; import { PART_DEFENSE } from "./roll/roll-part-defense.mjs";
import { RollDialogAdapter } from "./roll/roll-dialog-adapter.mjs"; import { DIFF, ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll/roll-constants.mjs";
import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll/roll-constants.mjs"; import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js";
import { OptionsAvancees, ROLL_DIALOG_V2, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js";
import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs"; import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs";
import { RollBasicParts } from "./roll/roll-basic-parts.mjs"; import { RollBasicParts } from "./roll/roll-basic-parts.mjs";
@@ -380,7 +379,7 @@ export class RdDCombat {
if (defenderToken && Misc.isFirstConnectedGM()) { if (defenderToken && Misc.isFirstConnectedGM()) {
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id) const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id)
rddCombat?.removeChatMessageActionsPasseArme(msg.paramChatDefense.attackerRoll.passeArme) rddCombat?.removeChatMessageActionsPasseArme(msg.paramChatDefense.attackerRoll.passeArme)
if (msg.defenderRoll.ids) {/* TODO: delete roll V1 */ if (msg.defenderRoll.v2) {/* TODO: delete roll V1 */
RollDialog.loadRollData(msg.paramChatDefense) RollDialog.loadRollData(msg.paramChatDefense)
rddCombat?._chatMessageDefenseV2(msg.paramChatDefense) rddCombat?._chatMessageDefenseV2(msg.paramChatDefense)
} else { } else {
@@ -561,7 +560,7 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
static isEchecTotal(rollData) { static isEchecTotal(rollData) {
if (rollData.ids /* roll V2*/) { if (rollData.v2 /* roll V2*/) {
// TODO: en cas de demi-surprise à l'attaque, tout échec est un echec total. // TODO: en cas de demi-surprise à l'attaque, tout échec est un echec total.
// TODO: en cas de demi-surprise en défense, pas de changement à la règle de base // TODO: en cas de demi-surprise en défense, pas de changement à la règle de base
return rollData.rolled.isETotal return rollData.rolled.isETotal
@@ -575,7 +574,7 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
static isParticuliere(rollData) { static isParticuliere(rollData) {
if (rollData.ids /* roll V2*/) { if (rollData.v2 /* roll V2*/) {
return rollData.rolled.isPart return rollData.rolled.isPart
} }
if (rollData.attackerRoll || !rollData.ajustements.surprise.used) { if (rollData.attackerRoll || !rollData.ajustements.surprise.used) {
@@ -586,7 +585,7 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
static isReussite(rollData) { static isReussite(rollData) {
if (rollData.ids /* roll V2*/) { if (rollData.v2 /* roll V2*/) {
return rollData.rolled.isSuccess return rollData.rolled.isSuccess
} }
if (!rollData.ajustements.surprise.used) { if (!rollData.ajustements.surprise.used) {
@@ -686,11 +685,7 @@ export class RdDCombat {
async doRollAttaque(rollData, callbacks = []) { async doRollAttaque(rollData, callbacks = []) {
// TODO V2 await this.proposerAjustementTirLancer(rollData) // TODO V2 await this.proposerAjustementTirLancer(rollData)
await RollDialog.create(rollData, { await RollDialog.create(rollData, {
onRollDone: (dialog) => { onRollDone: RollDialog.onRollDoneClose,
if (!OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST))
dialog.close()
},
customChatMessage: true,
callbacks: [ callbacks: [
async (roll) => await this.onAttaqueV2(roll), async (roll) => await this.onAttaqueV2(roll),
...callbacks ...callbacks
@@ -892,7 +887,10 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
isPossession(attackerRoll) { isPossession(attackerRoll) {
return attackerRoll.selectedCarac.label.toLowerCase() == 'possession'; const carac = attackerRoll.v2
? attackerRoll.current.carac?.label
: attackerRoll.selectedCarac.label
return carac?.toLowerCase() == 'possession';
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -1067,7 +1065,7 @@ export class RdDCombat {
opponentId: this.attackerId, opponentId: this.attackerId,
}, },
type: { allowed: [ROLL_TYPE_DEFENSE], current: ROLL_TYPE_DEFENSE }, type: { allowed: [ROLL_TYPE_DEFENSE], current: ROLL_TYPE_DEFENSE },
attackerRoll: RollDialogAdapter.mapActionAttaque(attackerRoll), attackerRoll: attackerRoll,
passeArme: attackerRoll.passeArme, passeArme: attackerRoll.passeArme,
}) })
} }
@@ -1075,7 +1073,6 @@ export class RdDCombat {
async doRollDefense(rollData, callbacks = []) { async doRollDefense(rollData, callbacks = []) {
await RollDialog.create(rollData, { await RollDialog.create(rollData, {
onRollDone: RollDialog.onRollDoneClose, onRollDone: RollDialog.onRollDoneClose,
customChatMessage: true,
callbacks: [ callbacks: [
async (roll) => { async (roll) => {
this.removeChatMessageActionsPasseArme(roll.passeArme); this.removeChatMessageActionsPasseArme(roll.passeArme);

View File

@@ -461,12 +461,7 @@ export class RdDCommands {
async supprimerSignesDraconiquesEphemeres() { async supprimerSignesDraconiquesEphemeres() {
if (game.user.isGM) { if (game.user.isGM) {
game.actors.forEach(actor => { game.actors.forEach(actor => actor.supprimerSignesDraconiques(it => it.system.ephemere))
const ephemeres = actor.items.filter(item => item.type = 'signedraconique' && item.system.ephemere);
if (ephemeres.length > 0) {
actor.deleteEmbeddedDocuments("Item", ephemeres.map(item => item.id));
}
});
} }
else { else {
ui.notifications.warn("Seul le MJ est autorisé à utiliser la commande /signe"); ui.notifications.warn("Seul le MJ est autorisé à utiliser la commande /signe");

View File

@@ -156,6 +156,11 @@ export class RdDResolutionTable {
} }
} }
/* -------------------------------------------- */
static replaceParticuliereDemiSurprise(chances){
foundry.utils.mergeObject(chances, reussites.find(x => x.code == 'part'), { overwrite: true });
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static significativeRequise(chances) { static significativeRequise(chances) {
chances.roll = Math.min(chances.part + 1, chances.sign) chances.roll = Math.min(chances.part + 1, chances.sign)

View File

@@ -25,7 +25,7 @@ export class RdDRollDialogEthylisme extends Dialog {
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html; this.html = html;
this.bringToTop(); this.bringToFront();
this.html.find(".force-alcool").change((event) => { this.html.find(".force-alcool").change((event) => {
this.rollData.forceAlcool = Misc.toInt(event.currentTarget.value); this.rollData.forceAlcool = Misc.toInt(event.currentTarget.value);

View File

@@ -22,7 +22,7 @@ export class RdDRollResolutionTable extends Dialog {
RdDRollResolutionTable.resolutionTable.render(true); RdDRollResolutionTable.resolutionTable.render(true);
} }
else{ else{
RdDRollResolutionTable.resolutionTable.bringToTop(); RdDRollResolutionTable.resolutionTable.bringToFront();
} }
} }
@@ -70,7 +70,7 @@ export class RdDRollResolutionTable extends Dialog {
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html; this.html = html;
this.bringToTop(); this.bringToFront();
this.html.find("[name='diffLibre']").val(Misc.toInt(this.rollData.diffLibre)); this.html.find("[name='diffLibre']").val(Misc.toInt(this.rollData.diffLibre));

View File

@@ -128,7 +128,7 @@ export class RdDRoll extends Dialog {
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html; this.html = html;
this.bringToTop(); this.bringToFront();
console.log('RdDRoll.activateListeners', this.rollData); console.log('RdDRoll.activateListeners', this.rollData);

View File

@@ -82,7 +82,7 @@ export class RdDTMRDialog extends Dialog {
this.subdialog = undefined this.subdialog = undefined
this.displaySize = undefined this.displaySize = undefined
if (!this.viewOnly && !game.user.isGM) { if (!this.viewOnly && !game.user.isGM) {
this.$tellToGM(this.actor.name + " monte dans les terres médianes (" + tmrData.mode + ")"); ChatUtility.tellToGM(this.actor.name + " monte dans les terres médianes (" + tmrData.mode + ")");
} }
this.callbacksOnAnimate = []; this.callbacksOnAnimate = [];
const displaySize = TMR_DISPLAY_SIZE.clamp(game.settings.get(SYSTEM_RDD, TMR_DISPLAY_SIZE.code) ?? TMR_DISPLAY_SIZE.def); const displaySize = TMR_DISPLAY_SIZE.clamp(game.settings.get(SYSTEM_RDD, TMR_DISPLAY_SIZE.code) ?? TMR_DISPLAY_SIZE.def);
@@ -125,7 +125,11 @@ export class RdDTMRDialog extends Dialog {
HtmlUtility.showControlWhen(this.html.find(".appliquerFatigue"), ReglesOptionnelles.isUsing("appliquer-fatigue")); HtmlUtility.showControlWhen(this.html.find(".appliquerFatigue"), ReglesOptionnelles.isUsing("appliquer-fatigue"));
HtmlUtility.showControlWhen(this.html.find(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(this._getCoordActor())); HtmlUtility.showControlWhen(this.html.find(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(this._getCoordActor()));
this.html.find('form.tmr-dialog *').click(event => this.subdialog?.bringToTop()); this.html.find('form.tmr-dialog *').click(event => {
if (this.subdialog?.rendered){
this.subdialog?.bringToFront()
}
})
// Roll Sort // Roll Sort
this.html.find('.lancer-sort').click(event => this.lancerUnSort()); this.html.find('.lancer-sort').click(event => this.lancerUnSort());
@@ -169,26 +173,26 @@ export class RdDTMRDialog extends Dialog {
async forceTMRDisplay() { async forceTMRDisplay() {
if (this.rendered) { if (this.rendered) {
this.bringToTop() this.bringToFront()
this.bringSubDialogToTop(); this.bringSubDialogToFront();
} }
} }
bringSubDialogToTop() { bringSubDialogToFront() {
if (this.subdialog?.bringToTop && this.subdialog?.element && this.subdialog?.element[0]) { if (this.subdialog?.bringToFront && this.subdialog?.element && this.subdialog?.element[0]) {
this.subdialog.bringToTop(); this.subdialog.bringToFront();
} }
} }
async restoreTMRAfterAction() { async restoreTMRAfterAction() {
this.subdialog = undefined this.subdialog = undefined
await this.maximize() await this.maximize()
this.bringToTop() this.bringToFront()
} }
forceTMRContinueAction() { forceTMRContinueAction() {
ui.notifications.warn('Vous devez finir votre action avant de continuer dans les TMR'); ui.notifications.warn('Vous devez finir votre action avant de continuer dans les TMR');
this.bringSubDialogToTop(); this.bringSubDialogToFront();
return false return false
} }
@@ -343,19 +347,8 @@ export class RdDTMRDialog extends Dialog {
this.forceTMRContinueAction() this.forceTMRContinueAction()
return false return false
} }
this.descenteTMR = true; this.descenteTMR = true
if (this.actor.tmrApp) { await await this.actor.quitterTMR(message, this.viewOnly, this.cumulFatigue)
this.actor.tmrApp = undefined // Cleanup reference
const appliquerFatigue = ReglesOptionnelles.isUsing("appliquer-fatigue")
await this.actor.santeIncDec(
appliquerFatigue ? "fatigue" : "endurance",
(appliquerFatigue ? 1 : -1) * this.cumulFatigue)
if (!this.viewOnly) {
await this.actor.setEffect(STATUSES.StatusDemiReve, false)
this.$tellToUserAndGM(message)
}
}
this.pixiTMR.close(); this.pixiTMR.close();
this.pixiTMR = undefined this.pixiTMR = undefined
await super.close(); await super.close();
@@ -412,7 +405,7 @@ export class RdDTMRDialog extends Dialog {
async $ignorerRencontre() { async $ignorerRencontre() {
if (this.currentRencontre) { if (this.currentRencontre) {
console.log("-> ignorer", this.currentRencontre); console.log("-> ignorer", this.currentRencontre);
this.$tellToGM(this.actor.name + " a ignoré: " + this.currentRencontre.name); ChatUtility.tellToGM(this.actor.name + " a ignoré: " + this.currentRencontre.name);
await this.$deleteRencontreTMRAtPosition() await this.$deleteRencontreTMRAtPosition()
this.updateTokens(); this.updateTokens();
this.$updateValuesDisplay(); this.$updateValuesDisplay();
@@ -578,29 +571,6 @@ export class RdDTMRDialog extends Dialog {
}, 500); }, 500);
} }
/* -------------------------------------------- */
_tellToUser(message) {
ChatMessage.create({ content: message, user: game.user.id, whisper: [game.user.id] });
}
/* -------------------------------------------- */
$tellToGM(message) {
ChatMessage.create({
user: game.user.id,
content: message,
whisper: ChatUtility.getGMs()
});
}
/* -------------------------------------------- */
$tellToUserAndGM(message) {
ChatMessage.create({
user: game.user.id,
content: message,
whisper: ChatUtility.getUserAndGMs()
})
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async manageRencontre(tmr) { async manageRencontre(tmr) {
if (this.viewOnly) { if (this.viewOnly) {
@@ -676,14 +646,14 @@ export class RdDTMRDialog extends Dialog {
? TMRUtility.getTMRType(tmr.coord) + " ??" ? TMRUtility.getTMRType(tmr.coord) + " ??"
: tmr.label + " (" + tmr.coord + ")"); : tmr.label + " (" + tmr.coord + ")");
this.setTMRPendingAction({ bringToTop: () => { } }) this.setTMRPendingAction({ bringToFront: () => { } })
const myRoll = await RdDDice.rollTotal("1dt", { showDice: SHOW_DICE }); const myRoll = await RdDDice.rollTotal("1dt", { showDice: SHOW_DICE });
this.restoreTMRAfterAction() this.restoreTMRAfterAction()
if (myRoll == 7) { if (myRoll == 7) {
this._tellToUser(myRoll + ": Rencontre en " + coordTMR); ChatUtility.tellToUser(myRoll + ": Rencontre en " + coordTMR);
return await game.system.rdd.rencontresTMR.getRencontreAleatoire(tmr, this.actor.isMauvaiseRencontre()) return await game.system.rdd.rencontresTMR.getRencontreAleatoire(tmr, this.actor.isMauvaiseRencontre())
} else { } else {
this._tellToUser(myRoll + ": Pas de rencontre en " + coordTMR); ChatUtility.tellToUser(myRoll + ": Pas de rencontre en " + coordTMR);
return undefined; return undefined;
} }
} }

View File

@@ -1,5 +1,5 @@
import { ChatUtility } from "../chat-utility.js" import { ChatUtility } from "../chat-utility.js"
import RollDialog from "./roll-dialog.mjs" import RollDialog, { ALL_ROLL_TYPES } from "./roll-dialog.mjs"
import { RdDCarac } from "../rdd-carac.js" import { RdDCarac } from "../rdd-carac.js"
import { RdDCombat } from "../rdd-combat.js" import { RdDCombat } from "../rdd-combat.js"
import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs" import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs"
@@ -8,6 +8,10 @@ import { RDD_CONFIG, renderTemplate } from "../constants.js"
import { EMPOIGNADE } from "../item/arme.js" import { EMPOIGNADE } from "../item/arme.js"
import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js" import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js"
import { RollTypeCuisine } from "./roll-type-cuisine.mjs" import { RollTypeCuisine } from "./roll-type-cuisine.mjs"
import { RollTypeMeditation } from "./roll-type-meditation.mjs"
import { PART_DEFENSE } from "./roll-part-defense.mjs"
import { PART_ATTAQUE } from "./roll-part-attaque.mjs"
import { RdDRollTables } from "../rdd-rolltables.js"
export default class ChatRollResult { export default class ChatRollResult {
static init() { static init() {
@@ -18,8 +22,11 @@ export default class ChatRollResult {
static onReady() { static onReady() {
foundry.applications.handlebars.loadTemplates({ foundry.applications.handlebars.loadTemplates({
'partial-infojet': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-infojet.hbs',
'partial-appel-chance': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-appel-chance.hbs', 'partial-appel-chance': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-appel-chance.hbs',
'partial-attaque-particuliere': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-attaque-particuliere.hbs', 'partial-attaque-particuliere': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-attaque-particuliere.hbs',
'partial-choix-maladresse': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-choix-maladresse.hbs',
'partial-maladresse': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-maladresse.hbs',
'partial-encaissement': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-encaissement.hbs', 'partial-encaissement': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-encaissement.hbs',
'partial-recul-choc': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-recul-choc.hbs', 'partial-recul-choc': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-recul-choc.hbs',
'partial-info-appel-moral': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-info-appel-moral.hbs', 'partial-info-appel-moral': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-info-appel-moral.hbs',
@@ -38,7 +45,7 @@ export default class ChatRollResult {
) )
const save = RollDialog.saveParts(roll, impacts) const save = RollDialog.saveParts(roll, impacts)
ChatUtility.setMessageData(chatMessage, 'rollData', save) await this.saveChatMessageRoll(chatMessage, save)
return chatMessage return chatMessage
} }
@@ -48,7 +55,7 @@ export default class ChatRollResult {
roll.show.chance = this.isAppelChancePossible(roll) roll.show.chance = this.isAppelChancePossible(roll)
roll.show.encaissement = this.isShowEncaissement(roll) roll.show.encaissement = this.isShowEncaissement(roll)
roll.show.recul = this.getRecul(roll) roll.show.recul = this.getRecul(roll)
//roll.show.particuliere = roll.show.particuliere ?? [] roll.show.maladresse = this.getMaladresse(roll)
} }
isAppelChancePossible(roll) { isAppelChancePossible(roll) {
@@ -65,6 +72,23 @@ export default class ChatRollResult {
return false return false
} }
getMaladresse(roll) {
switch (roll.type.current) {
case ROLL_TYPE_DEFENSE:
if (roll.rolled.isETotal) {
const arme = roll.current[PART_DEFENSE].arme
return arme ? 'avec-arme' : 'sans-arme'
}
break
case ROLL_TYPE_ATTAQUE:
if (roll.rolled.isETotal || (roll.rolled.isEchec && roll.active.surprise == 'demi')) {
const arme = roll.current[PART_ATTAQUE].arme
return arme.system.baseInit > 4 ? 'avec-arme' : 'sans-arme'
}
break
}
return undefined
}
getRecul(roll, defender = roll.active.actor, attacker = roll.opponent?.actor) { getRecul(roll, defender = roll.active.actor, attacker = roll.opponent?.actor) {
switch (roll.type.current) { switch (roll.type.current) {
@@ -100,7 +124,7 @@ export default class ChatRollResult {
} }
async buildRollHtml(roll) { async buildRollHtml(roll) {
const template = `systems/foundryvtt-reve-de-dragon/templates/roll/result/chat-${roll.type.current}.hbs` const template = ALL_ROLL_TYPES.find(it => it.code == roll.type.current).chatResultTemplate
const html = await renderTemplate(template, roll) const html = await renderTemplate(template, roll)
return await RdDTextEditor.enrichHTML(html, undefined, { showLink: false }) return await RdDTextEditor.enrichHTML(html, undefined, { showLink: false })
} }
@@ -112,7 +136,9 @@ export default class ChatRollResult {
$(html).on("click", '.resister-recul', event => this.onClickRecul(event)) $(html).on("click", '.resister-recul', event => this.onClickRecul(event))
$(html).on("click", '.choix-particuliere', event => this.onClickChoixParticuliere(event)) $(html).on("click", '.choix-particuliere', event => this.onClickChoixParticuliere(event))
$(html).on("click", '.faire-gouter', event => this.onClickFaireGouter(event)) $(html).on("click", '.faire-gouter', event => this.onClickFaireGouter(event))
$(html).on("click", '.monter-tmr-normale', event => this.onClickMonteeTMR(event, 'normal'))
$(html).on("click", '.monter-tmr-rapide', event => this.onClickMonteeTMR(event, 'rapide'))
$(html).on("click", '.tirer-maladresse', event => this.onClickTirerMaladresse(event))
} }
getCombat(roll) { getCombat(roll) {
@@ -120,15 +146,24 @@ export default class ChatRollResult {
case ROLL_TYPE_DEFENSE: case ROLL_TYPE_DEFENSE:
return RdDCombat.rddCombatForAttackerAndDefender(roll.ids.opponentId, roll.ids.opponentTokenId, roll.ids.actorTokenId) return RdDCombat.rddCombatForAttackerAndDefender(roll.ids.opponentId, roll.ids.opponentTokenId, roll.ids.actorTokenId)
case ROLL_TYPE_ATTAQUE: case ROLL_TYPE_ATTAQUE:
return RdDCombat.rddCombatForAttackerAndDefender(roll.ids.actorId, roll.ids.actorTokenId, roll.ids.opponentId) return RdDCombat.rddCombatForAttackerAndDefender(roll.ids.actorId, roll.ids.actorTokenId, roll.ids.opponentTokenId)
} }
return undefined return undefined
} }
async saveChatMessageRoll(chatMessage, savedRoll) {
await ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll)
}
loadChatMessageRoll(chatMessage) {
return ChatUtility.getMessageData(chatMessage, 'rollData')
}
async updateChatMessage(chatMessage, savedRoll) { async updateChatMessage(chatMessage, savedRoll) {
ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll) await this.saveChatMessageRoll(chatMessage, savedRoll)
const copy = foundry.utils.duplicate(savedRoll) const copy = foundry.utils.duplicate(savedRoll)
RollDialog.loadRollData(copy) RollDialog.loadRollData(copy)
savedRoll.dmg = copy.current.attaque?.dmg
this.prepareDisplay(copy) this.prepareDisplay(copy)
chatMessage.update({ content: await this.buildRollHtml(copy) }) chatMessage.update({ content: await this.buildRollHtml(copy) })
chatMessage.render(true) chatMessage.render(true)
@@ -136,7 +171,7 @@ export default class ChatRollResult {
onClickAppelChance(event) { onClickAppelChance(event) {
const chatMessage = ChatUtility.getChatMessage(event) const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') const savedRoll = this.loadChatMessageRoll(chatMessage)
const actor = game.actors.get(savedRoll.ids.actorId) const actor = game.actors.get(savedRoll.ids.actorId)
actor.rollAppelChance( actor.rollAppelChance(
() => this.onAppelChanceSuccess(savedRoll, chatMessage), () => this.onAppelChanceSuccess(savedRoll, chatMessage),
@@ -144,11 +179,13 @@ export default class ChatRollResult {
event.preventDefault() event.preventDefault()
} }
onAppelChanceSuccess(savedRoll, chatMessage) { async onAppelChanceSuccess(savedRoll, chatMessage) {
const reRoll = foundry.utils.duplicate(savedRoll) const reRoll = foundry.utils.duplicate(savedRoll)
console.log('onAppelChanceSuccess savedRoll', savedRoll) console.log('onAppelChanceSuccess savedRoll', savedRoll)
reRoll.type.retry = true reRoll.type.retry = true
await this.updateChatMessage(chatMessage, reRoll)
const callbacks = [r => ChatUtility.removeChatMessageId(chatMessage.id)] const callbacks = [r => ChatUtility.removeChatMessageId(chatMessage.id)]
// TODO: annuler les effets // TODO: annuler les effets
switch (reRoll.type.current) { switch (reRoll.type.current) {
case ROLL_TYPE_DEFENSE: case ROLL_TYPE_DEFENSE:
@@ -171,7 +208,7 @@ export default class ChatRollResult {
onClickAppelDestinee(event) { onClickAppelDestinee(event) {
const chatMessage = ChatUtility.getChatMessage(event) const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') const savedRoll = this.loadChatMessageRoll(chatMessage)
const actor = game.actors.get(savedRoll.ids.actorId) const actor = game.actors.get(savedRoll.ids.actorId)
actor.appelDestinee(async () => { actor.appelDestinee(async () => {
@@ -184,7 +221,7 @@ export default class ChatRollResult {
async onClickEncaissement(event) { async onClickEncaissement(event) {
const chatMessage = ChatUtility.getChatMessage(event) const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') const savedRoll = this.loadChatMessageRoll(chatMessage)
const attaque = savedRoll.attackerRoll const attaque = savedRoll.attackerRoll
const defender = game.actors.get(savedRoll.ids.actorId) const defender = game.actors.get(savedRoll.ids.actorId)
const attacker = game.actors.get(savedRoll.ids.opponentId) const attacker = game.actors.get(savedRoll.ids.opponentId)
@@ -198,7 +235,7 @@ export default class ChatRollResult {
async onClickRecul(event) { async onClickRecul(event) {
const chatMessage = ChatUtility.getChatMessage(event) const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') const savedRoll = this.loadChatMessageRoll(chatMessage)
const defender = game.actors.get(savedRoll.ids.actorId) const defender = game.actors.get(savedRoll.ids.actorId)
const attacker = game.actors.get(savedRoll.ids.opponentId) const attacker = game.actors.get(savedRoll.ids.opponentId)
savedRoll.done.recul = await defender.encaisserRecul(attacker.getForce(), savedRoll.attackerRoll.dmg.dmgArme) savedRoll.done.recul = await defender.encaisserRecul(attacker.getForce(), savedRoll.attackerRoll.dmg.dmgArme)
@@ -209,15 +246,37 @@ export default class ChatRollResult {
async onClickChoixParticuliere(event) { async onClickChoixParticuliere(event) {
const choix = event.currentTarget.attributes['data-particuliere'].value const choix = event.currentTarget.attributes['data-particuliere'].value
const chatMessage = ChatUtility.getChatMessage(event) const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') const savedRoll = this.loadChatMessageRoll(chatMessage)
savedRoll.particuliere = choix savedRoll.particuliere = choix
savedRoll.particulieres = [RDD_CONFIG.particuliere[choix]] savedRoll.particulieres = [RDD_CONFIG.particuliere[choix]]
await this.updateChatMessage(chatMessage, savedRoll) await this.updateChatMessage(chatMessage, savedRoll)
await this.getCombat(savedRoll)?.onAttaqueV2(savedRoll, callbacks) await this.getCombat(savedRoll)?.onAttaqueV2(savedRoll)
} }
async onClickFaireGouter(event) { async onClickFaireGouter(event) {
const chatMessage = ChatUtility.getChatMessage(event) const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') const savedRoll = this.loadChatMessageRoll(chatMessage)
if (!savedRoll.type.retry) {
savedRoll.type.retry = true
await this.updateChatMessage(chatMessage, savedRoll)
}
await new RollTypeCuisine().onFaireGouter(savedRoll) await new RollTypeCuisine().onFaireGouter(savedRoll)
} }
async onClickMonteeTMR(event, mode) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
if (await new RollTypeMeditation().onMonteeTMR(savedRoll, mode)) {
savedRoll.done.meditation = true
await this.updateChatMessage(chatMessage, savedRoll)
}
}
async onClickTirerMaladresse(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const typeMaladresse = event.currentTarget.attributes['data-maladresse'].value
const savedRoll = this.loadChatMessageRoll(chatMessage)
savedRoll.maladresse = await RdDRollTables.getMaladresse({ arme: typeMaladresse == 'avec-arme', toChat: false })
savedRoll.type.retry = true
await this.updateChatMessage(chatMessage, savedRoll)
}
} }

View File

@@ -13,7 +13,6 @@ export const ATTAQUE_ROLL_TYPES = [ROLL_TYPE_ATTAQUE]
export const COMBAT_ROLL_TYPES = [ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE] export const COMBAT_ROLL_TYPES = [ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE]
export const DEMIREVE_ROLL_TYPES = [ROLL_TYPE_SORT] export const DEMIREVE_ROLL_TYPES = [ROLL_TYPE_SORT]
export const DEFAULT_ROLL_TYPES = [ROLL_TYPE_COMP, ROLL_TYPE_TACHE, ROLL_TYPE_MEDITATION, ROLL_TYPE_CUISINE, ROLL_TYPE_OEUVRE, ROLL_TYPE_JEU] export const DEFAULT_ROLL_TYPES = [ROLL_TYPE_COMP, ROLL_TYPE_TACHE, ROLL_TYPE_MEDITATION, ROLL_TYPE_CUISINE, ROLL_TYPE_OEUVRE, ROLL_TYPE_JEU]
export const ALL_ROLL_TYPES = [...DEFAULT_ROLL_TYPES, ...COMBAT_ROLL_TYPES, ...DEMIREVE_ROLL_TYPES]
export const DIFF = { export const DIFF = {

View File

@@ -8,7 +8,7 @@ import { RdDItemArme } from "../item/arme.js";
import { RdDBonus } from "../rdd-bonus.js"; import { RdDBonus } from "../rdd-bonus.js";
import { ITEM_TYPES, RDD_CONFIG } from "../constants.js"; import { ITEM_TYPES, RDD_CONFIG } from "../constants.js";
import { CARACS } from "../rdd-carac.js"; import { CARACS } from "../rdd-carac.js";
import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_OEUVRE } from "./roll-constants.mjs"; import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE, ROLL_TYPE_OEUVRE } from "./roll-constants.mjs";
import { PART_ATTAQUE } from "./roll-part-attaque.mjs"; import { PART_ATTAQUE } from "./roll-part-attaque.mjs";
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -27,7 +27,8 @@ export class RollDialogAdapter {
RollDialogAdapter.setRollDataRolled(rollData, rolled, rollTitle) RollDialogAdapter.setRollDataRolled(rollData, rolled, rollTitle)
RollDialogAdapter.adjustRollDataForV1(rollData) RollDialogAdapter.adjustRollDataForV1(rollData)
RollDialogAdapter.adjustAttaqueParticuliere(rollData) RollDialogAdapter.adjustAttaqueParticuliere(rollData)
RollDialogAdapter.adjustAttaqueDmg(rollData)
RollDialogAdapter.adjustDemiSurprise(rollData)
return rolled return rolled
} }
@@ -95,16 +96,27 @@ export class RollDialogAdapter {
rolled.niveauNecessaire = RdDResolutionTable.findNiveauNecessaire(rollData.selectedCarac.value, rolled.roll) rolled.niveauNecessaire = RdDResolutionTable.findNiveauNecessaire(rollData.selectedCarac.value, rolled.roll)
rolled.ajustementNecessaire = rolled.niveauNecessaire - diff rolled.ajustementNecessaire = rolled.niveauNecessaire - diff
} }
rollData.ajustements = rollData.ajustements.map(aj => { rollData.ajustements = rollData.ajustements.map(aj => { return { label: aj.label, value: aj.value } })
return {
used: true,
label: aj.label,
value: aj.diff,
descr: aj.diff == undefined ? aj.label : undefined
}
})
} }
static adjustDemiSurprise(rollData) {
if (rollData.active.surprise == 'demi' && rollData.rolled.isPart) {
RdDResolutionTable.replaceParticuliereDemiSurprise(rollData.rolled)
}
}
static adjustAttaqueDmg(rollData) {
switch (rollData.type.current) {
case ROLL_TYPE_ATTAQUE:
rollData.dmg = RdDBonus.dmgRollV2(rollData, rollData.current.attaque)
break
case ROLL_TYPE_DEFENSE:
rollData.dmg = RdDBonus.dmgRollV2(rollData.attackerRoll, rollData.attackerRoll.current.attaque)
break
}
}
static adjustAttaqueParticuliere(rollData) { static adjustAttaqueParticuliere(rollData) {
if (rollData.type.current != ROLL_TYPE_ATTAQUE || !rollData.rolled.isPart) { if (rollData.type.current != ROLL_TYPE_ATTAQUE || !rollData.rolled.isPart) {
return return

View File

@@ -48,7 +48,7 @@ import { ActorImpacts } from "../technical/actor-impacts.mjs";
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api
const ALL_ROLL_TYPES = [ export const ALL_ROLL_TYPES = [
new RollTypeComp(), new RollTypeComp(),
new RollTypeTache(), new RollTypeTache(),
new RollTypeAttaque(), new RollTypeAttaque(),
@@ -173,15 +173,16 @@ const ROLL_PARTS = [
/* -------------------------------------------- */ /* -------------------------------------------- */
export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2) export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2)
{ {
static onRollDoneDoNothing(dialog) { static onCloseDoNothing() {
}
static onRollDoneDoNothing(dialog, roll) {
dialog.render() dialog.render()
} }
static onRollDoneClose(dialog) { static onRollDoneClose(dialog, roll) {
if (!OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST)) if (roll.type.retry || !OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST))
dialog.close() dialog.close()
} }
static init() { static init() {
} }
@@ -198,7 +199,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
ChatRollResult.onReady() ChatRollResult.onReady()
foundry.applications.handlebars.loadTemplates(ALL_ROLL_TYPES.map(m => m.template)) foundry.applications.handlebars.loadTemplates(ALL_ROLL_TYPES.map(m => m.chatResultTemplate))
foundry.applications.handlebars.loadTemplates(ROLL_PARTS.map(p => p.template)) foundry.applications.handlebars.loadTemplates(ROLL_PARTS.map(p => p.template))
ROLL_PARTS.forEach(p => p.onReady()) ROLL_PARTS.forEach(p => p.onReady())
@@ -236,6 +237,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
static async create(rollData, rollOptions = {}) { static async create(rollData, rollOptions = {}) {
const rollDialog = new RollDialog(rollData, rollOptions) const rollDialog = new RollDialog(rollData, rollOptions)
rollDialog.render(true) rollDialog.render(true)
return rollDialog
} }
static get PARTS() { static get PARTS() {
@@ -314,6 +316,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
constructor(rollData, rollOptions) { constructor(rollData, rollOptions) {
super() super()
this.hooks = []
this.rollData = RollDialog.$prepareRollData(rollData) this.rollData = RollDialog.$prepareRollData(rollData)
this.rollOptions = { this.rollOptions = {
callbacks: [ callbacks: [
@@ -321,13 +324,28 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
async r => await r.active.actor.appliquerAppelMoral(r), async r => await r.active.actor.appliquerAppelMoral(r),
...(rollOptions.callbacks ?? []) ...(rollOptions.callbacks ?? [])
], ],
customChatMessage: rollOptions.customChatMessage, onRollDone: rollOptions.onRollDone ?? RollDialog.onRollDoneDoNothing,
onRollDone: rollOptions.onRollDone ?? RollDialog.onRollDoneDoNothing onClose: rollOptions.onClose ?? RollDialog.onCloseDoNothing
} }
this.chatRollResult = new ChatRollResult(); this.chatRollResult = new ChatRollResult()
this.selectType() this.selectType()
this.registerHooks(rollData);
} }
registerHooks(rollData) {
ROLL_PARTS.filter(p => p.isValid(rollData))
.forEach(p => p.getHooks(this).forEach(h => {
const hook = h.hook;
const id = Hooks.on(hook, h.fn)
this.hooks.push({ hook, id })
}))
}
unregisterHooks() {
this.hooks.forEach(h => Hooks.off(h.hook, h.id))
}
selectType() { selectType() {
const selectedType = this.getSelectedType(); const selectedType = this.getSelectedType();
this.rollData.type.label = selectedType.title(this.rollData) this.rollData.type.label = selectedType.title(this.rollData)
@@ -383,7 +401,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
return RollDialog.getActiveParts(rollData) return RollDialog.getActiveParts(rollData)
.map(p => p.getAjustements(rollData)) .map(p => p.getAjustements(rollData))
.reduce((a, b) => a.concat(b)) .reduce((a, b) => a.concat(b))
.sort((a, b) => a.diff == undefined ? 1 : b.diff == undefined ? -1 : 0) .sort((a, b) => a.value == undefined ? 1 : b.value == undefined ? -1 : 0)
} }
async buildHTMLTable(carac, diff) { async buildHTMLTable(carac, diff) {
@@ -405,7 +423,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
visibleRollParts.forEach(p => p.prepareContext(rollData)) visibleRollParts.forEach(p => p.prepareContext(rollData))
RollDialog.calculAjustements(rollData) RollDialog.calculAjustement(rollData)
const templates = RollDialog.getActiveParts(rollData).map(p => p.toTemplateData()) const templates = RollDialog.getActiveParts(rollData).map(p => p.toTemplateData())
const context = await super._prepareContext() const context = await super._prepareContext()
@@ -427,12 +445,11 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
} }
} }
static calculAjustements(rollData) { static calculAjustement(rollData) {
rollData.ajustements = RollDialog.getAjustements(rollData) rollData.ajustements = RollDialog.getAjustements(rollData)
rollData.ajustements.forEach(it => it.isDiff = it.diff != undefined)
rollData.current.totaldiff = rollData.ajustements rollData.current.totaldiff = rollData.ajustements
.map(adj => adj.diff) .filter(a => a.value != undefined)
.filter(d => d != undefined) .map(a => a.value)
.reduce(Misc.sum(), 0) .reduce(Misc.sum(), 0)
} }
@@ -440,20 +457,25 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
return ALL_ROLL_TYPES.find(m => m.code == this.rollData.type.current) return ALL_ROLL_TYPES.find(m => m.code == this.rollData.type.current)
} }
async close(options) {
if (this.rollOptions.onClose) {
this.rollOptions.onClose()
}
this.unregisterHooks()
return await super.close(options)
}
async roll() { async roll() {
const roll = RollDialog.saveParts(this.rollData) const roll = RollDialog.saveParts(this.rollData)
this.loadRollData(roll) RollDialog.loadRollData(roll)
const selectedRollType = this.getSelectedType(roll); const selectedRollType = this.getSelectedType(roll);
selectedRollType.onSelect(roll) selectedRollType.onSelect(roll)
roll.current.resultat = this.rollData.current[PART_TRICHER]?.resultat ?? -1 roll.current.resultat = this.rollData.current[PART_TRICHER]?.resultat ?? -1
roll.choix = {} roll.choix = {}
roll.rolled = await RollDialogAdapter.rollDice(roll, this.rollTitle(roll)) roll.rolled = await RollDialogAdapter.rollDice(roll, this.rollTitle(roll))
const impacts = { const impacts = new ActorImpacts(roll.active)
active: new ActorImpacts(roll.active),
opponent: roll.opponent ? new ActorImpacts(roll.opponent) : undefined
}
roll.result = selectedRollType.getResult(roll, impacts) roll.result = selectedRollType.getResult(roll, impacts)
@@ -465,17 +487,17 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
await Promise.all(callbacks.map(async callback => await callback(roll))) await Promise.all(callbacks.map(async callback => await callback(roll)))
await impacts.active?.applyImpacts() await impacts.applyImpacts()
await impacts.opponent?.applyImpacts()
selectedRollType.onApplyImpacts(roll, impacts) selectedRollType.onApplyImpacts(roll, impacts)
await this.chatRollResult.display(roll, impacts) await this.chatRollResult.display(roll, impacts)
this.rollOptions.onRollDone(this) this.rollOptions.onRollDone(this, roll)
} }
loadRollData(roll) { static loadRollData(roll) {
RollDialog.$prepareRollData(roll) RollDialog.$prepareRollData(roll)
RollDialog.calculAjustements(roll) RollDialog.calculAjustement(roll)
roll.v2 = true roll.v2 = true
return roll
} }
async defaultCallback(roll, rolled) { async defaultCallback(roll, rolled) {

View File

@@ -50,14 +50,6 @@ export class RollPartAttaque extends RollPartSelect {
choices(refs) { return refs.attaques } choices(refs) { return refs.attaques }
static $extractAttaque(attaque, actor) { static $extractAttaque(attaque, actor) {
// const extracted = foundry.utils.mergeObject({
// key: `${attaque.action}::${attaque.label}`,
// tactique: TACTIQUES[0]
// },
// attaque
// )
// return extracted
// extracted.initialDiff = attaque.comp?.system.default_diffLibre ?? 0
attaque.key = `${attaque.action}::${attaque.label}` attaque.key = `${attaque.action}::${attaque.label}`
attaque.tactique = TACTIQUES[0] attaque.tactique = TACTIQUES[0]
attaque.initialDiff = attaque.comp?.system.default_diffLibre ?? 0 attaque.initialDiff = attaque.comp?.system.default_diffLibre ?? 0
@@ -71,14 +63,9 @@ export class RollPartAttaque extends RollPartSelect {
getAjustements(rollData) { getAjustements(rollData) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
const ajustements = [] const tactique = current.tactique ? [{ label: current.tactique.label, value: current.tactique.attaque }] : []
if (current.tactique) { const surprise = rollData.opponent?.surprise ? [{ label: rollData.opponent.surprise.label, value: rollData.opponent.surprise.attaque }] : []
ajustements.push({ label: current.tactique.label, diff: current.tactique.attaque }) return [...tactique, ...surprise]
}
if (rollData.opponent?.surprise) {
ajustements.push({ label: rollData.opponent.surprise.label, diff: rollData.opponent.surprise.attaque })
}
return ajustements
} }

View File

@@ -35,7 +35,7 @@ export class RollPartCheckbox extends RollPart {
getAjustements(rollData) { getAjustements(rollData) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
if (current.checked) { if (current.checked) {
return [{ label: this.getCheckboxLabelAjustement(rollData), diff: current.value }] return [{ label: this.getCheckboxLabelAjustement(rollData), value: current.value }]
} }
return [] return []
} }

View File

@@ -47,7 +47,7 @@ export class RollPartCoeur extends RollPartSelect {
if (current.key != '') { if (current.key != '') {
return [{ return [{
label: "Coeur pour " + current.label, label: "Coeur pour " + current.label,
diff: current.value value: current.value
}] }]
} }
return [] return []

View File

@@ -57,7 +57,7 @@ export class RollPartConditions extends RollPart {
getAjustements(rollData) { getAjustements(rollData) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
if (current.value != 0) { if (current.value != 0) {
return [{ label: DESCR_CONDITIONS, diff: current.value }] return [{ label: DESCR_CONDITIONS, value: current.value }]
} }
return [] return []
} }

View File

@@ -1,9 +1,6 @@
import { ITEM_TYPES } from "../constants.js" import { ITEM_TYPES } from "../constants.js"
import { Grammar } from "../grammar.js"
import { ATTAQUE_TYPE, RdDItemArme } from "../item/arme.js" import { ATTAQUE_TYPE, RdDItemArme } from "../item/arme.js"
import { RdDBonus } from "../rdd-bonus.js"
import { CARACS } from "../rdd-carac.js" import { CARACS } from "../rdd-carac.js"
import { StatusEffects } from "../settings/status-effects.js"
import { DIFF, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs" import { DIFF, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs" import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP } from "./roll-part-comp.mjs" import { PART_COMP } from "./roll-part-comp.mjs"
@@ -113,7 +110,7 @@ export class RollPartDefense extends RollPartSelect {
isArmeDisparate(rollData) { isArmeDisparate(rollData) {
const armeDefense = this.getCurrent(rollData).arme const armeDefense = this.getCurrent(rollData).arme
if (armeDefense) { if (armeDefense) {
const armeAttaque = rollData.attackerRoll?.arme const armeAttaque = rollData.attackerRoll?.current.attaque.arme
return RdDItemArme.defenseArmeParade(armeAttaque, armeDefense) == 'sign' return RdDItemArme.defenseArmeParade(armeAttaque, armeDefense) == 'sign'
} }
return false return false
@@ -126,7 +123,11 @@ export class RollPartDefense extends RollPartSelect {
return { diff: 0, type: DIFF.LIBRE } return { diff: 0, type: DIFF.LIBRE }
} }
else { else {
return { diff: rollData.attackerRoll.diff ?? 0, type: DIFF.DEFENSE } const attackerRoll = rollData.attackerRoll
const diff = attackerRoll.v2
? attackerRoll.selected.diff.value
: attackerRoll.diff
return { diff: diff ?? 0, type: DIFF.DEFENSE }
} }
} }
} }

View File

@@ -66,7 +66,7 @@ export class RollPartDiff extends RollPart {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
return [{ return [{
label: current.label, label: current.label,
diff: current.value value: current.value
}] }]
} }

View File

@@ -81,7 +81,9 @@ export class RollPartJeu extends RollPartSelect {
$selectJeu(rollData, key) { $selectJeu(rollData, key) {
this.selectByKey(rollData, key, 0) this.selectByKey(rollData, key, 0)
RollPartJeu.forceCompJeu(rollData) if (rollData.type.current == ROLL_TYPE_JEU) {
RollPartJeu.forceCompJeu(rollData)
}
} }
static forceCompJeu(rollData) { static forceCompJeu(rollData) {

View File

@@ -72,9 +72,10 @@ export class RollPartMeditation extends RollPartSelect {
} }
getAjustements(rollData) { getAjustements(rollData) {
const malusEchecs = { label: "Méditation", diff: this.getMalusEchecs(rollData) } const malus = this.getMalusEchecs(rollData)
const malusConditions = { label: "Conditions", diff: this.getMalusConditions(rollData) } const malusEchecs = malusEchecs == 0 ? [] : [{ label: "Méditation", value: malus }]
return [malusConditions, ...(malusEchecs.diff == 0 ? [] : [malusEchecs])] const malusConditions = { label: "Conditions", value: this.getMalusConditions(rollData) }
return [malusConditions, ...malusEchecs]
} }
$selectMeditation(rollData, key) { $selectMeditation(rollData, key) {

View File

@@ -16,7 +16,7 @@ export class RollPartSelect extends RollPart {
getAjustements(rollData) { getAjustements(rollData) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
if (current) { if (current) {
return [{ label: current.label, diff: current.value }] return [{ label: current.label, value: current.value }]
} }
return [] return []
} }

View File

@@ -76,8 +76,8 @@ export class RollPartSign extends RollPart {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
if (current.surprise == 'demi') { if (current.surprise == 'demi') {
return [ return [
{ label: 'Significative requise ' + Misc.getFractionOneN(current.diviseur), diff: undefined }, { label: 'Significative requise ' + Misc.getFractionOneN(current.diviseur) },
...current.reasons.map(it => { return { label: '<i class="fa-solid fa-triangle-exclamation"></i> ' + it, diff: undefined } }) ...current.reasons.map(it => { return { label: '<i class="fa-solid fa-triangle-exclamation"></i> ' + it } })
] ]
} }
return [] return []

View File

@@ -22,9 +22,27 @@ export class RollPartSort extends RollPartSelect {
isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() } isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() }
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_SORT) } visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_SORT) }
restore(rollData) {
const saved = this.getSaved(rollData)
this.setCurrent(rollData, {
key: saved.key,
isReserve: saved.isReserve,
ptreve: saved.ptreve
})
}
store(rollData, targetData) {
const current = this.getCurrent(rollData)
this.setSaved(targetData, {
key: current.key,
isReserve: current.isReserve,
ptreve: current.ptreve
})
}
loadRefs(rollData) { loadRefs(rollData) {
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
const coord = rollData.active.actor.system.reve.tmrpos.coord const coord = this.getCoord(rollData)
const draconics = rollData.active.actor.getDraconics() const draconics = rollData.active.actor.getDraconics()
const sorts = rollData.active.actor.itemTypes[ITEM_TYPES.sort] const sorts = rollData.active.actor.itemTypes[ITEM_TYPES.sort]
.map(s => RollPartSort.$extractSort(s, coord, draconics)) .map(s => RollPartSort.$extractSort(s, coord, draconics))
@@ -33,7 +51,7 @@ export class RollPartSort extends RollPartSelect {
{ {
coord: coord, coord: coord,
tmr: TMRUtility.getTMR(coord), tmr: TMRUtility.getTMR(coord),
reve: rollData.active.actor.system.reve.reve.value, reve: this.getReveActuel(rollData),
draconics: draconics, draconics: draconics,
all: sorts, all: sorts,
sorts: sorts.filter(it => RdDItemSort.isSortOnCoord(it.sort, coord)) sorts: sorts.filter(it => RdDItemSort.isSortOnCoord(it.sort, coord))
@@ -41,10 +59,18 @@ export class RollPartSort extends RollPartSelect {
{ inplace: true } { inplace: true }
) )
if (refs.sorts.length > 0) { if (refs.sorts.length > 0) {
this.$selectSort(rollData) this.$selectSort(rollData, this.getSaved(rollData))
} }
} }
getReveActuel(rollData) {
return rollData.active.actor.system.reve.reve.value
}
getCoord(rollData) {
return rollData.active.actor.system.reve.tmrpos.coord
}
choices(refs) { return refs.sorts } choices(refs) { return refs.sorts }
static $extractSort(sort, coord, draconics) { static $extractSort(sort, coord, draconics) {
@@ -56,37 +82,35 @@ export class RollPartSort extends RollPartSelect {
value: isDiffVariable ? -7 : parseInt(sort.system.difficulte), value: isDiffVariable ? -7 : parseInt(sort.system.difficulte),
ptreve: isReveVariable ? 1 : sort.system.ptreve, ptreve: isReveVariable ? 1 : sort.system.ptreve,
caseTMR: RdDItemSort.getCaseTMR(sort), caseTMR: RdDItemSort.getCaseTMR(sort),
bonusCase: RdDItemSort.getCaseBonus(sort, coord),
isDiffVariable: isDiffVariable, isDiffVariable: isDiffVariable,
isReveVariable: isReveVariable, isReveVariable: isReveVariable,
isReserve: false, isReserve: false,
sort: sort, sort: sort,
draconics: RdDItemSort.getDraconicsSort(draconics, sort).map(it => it.name) draconics: RdDItemSort.getDraconicsSort(draconics, sort).map(it => it.name),
} }
} }
getAjustements(rollData) { getAjustements(rollData) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
if (current) { if (current) {
const reserve = current.isReserve ? const sort = { label: current.label, value: current.value }
[{ label: `Mise en réserve en ${current.coord}` }] : [] const reserve = current.isReserve ? [{ label: `Mise en réserve en ${this.getCoord(rollData)}` }] : []
const bonusCase = current.bonusCase ? const bonusCase = current.bonusCase ? [{ label: `Bonus case +${current.bonusCase}%` }] : []
[{ label: `Bonus case +${current.bonusCase}%` }] : [] const reve = { label: `Rêve ${current.ptreve}` }
return [ return [sort, ...bonusCase, reve, ...reserve]
{ label: current.label, diff: current.value },
{ label: `r${current.ptreve}` },
...bonusCase,
...reserve
]
} }
return [] return []
} }
$selectSort(rollData, key) { $selectSort(rollData, values) {
const previous = this.getCurrent(rollData) const current = this.selectByKey(rollData, values.key)
const current = this.selectByKey(rollData, key, -7) if (values.ptreve) {
if (current.key != previous.key) { } current.ptreve = values.ptreve
current.bonusCase = RdDItemSort.getCaseBonus(current.sort, }
rollData.active.actor.system.reve.tmrpos.coord) if (values.isReserve != undefined) {
current.isReserve = values.isReserve
}
} }
async _onRender(rollDialog, context, options) { async _onRender(rollDialog, context, options) {
@@ -99,7 +123,7 @@ export class RollPartSort extends RollPartSelect {
selectSort.addEventListener("change", e => { selectSort.addEventListener("change", e => {
const selectOptions = e.currentTarget.options const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex const index = selectOptions.selectedIndex
this.$selectSort(rollDialog.rollData, selectOptions[index]?.value) this.$selectSort(rollDialog.rollData, { key: selectOptions[index]?.value })
rollDialog.render() rollDialog.render()
}) })

View File

@@ -18,10 +18,12 @@ export class RollPartTache extends RollPartSelect {
loadRefs(rollData) { loadRefs(rollData) {
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
const selected = this.getSelected(rollData) const selected = this.getSelected(rollData)
refs.forced = selected.forced
refs.all = rollData.active.actor.itemTypes[ITEM_TYPES.tache] refs.all = rollData.active.actor.itemTypes[ITEM_TYPES.tache]
.filter(tache => !selected.forced || tache.id == selected.key) .filter(tache => !selected.forced || tache.id == selected.key)
.filter(tache => tache.system.points_de_tache_courant < tache.system.points_de_tache) .filter(tache => tache.system.points_de_tache_courant < tache.system.points_de_tache)
.map(tache => RollPartTache.$extractTache(tache, rollData.active.actor)) .map(tache => RollPartTache.$extractTache(tache, rollData.active.actor))
refs.taches = refs.all refs.taches = refs.all
if (refs.taches.length > 0) { if (refs.taches.length > 0) {
this.$selectTache(rollData) this.$selectTache(rollData)
@@ -46,6 +48,8 @@ export class RollPartTache extends RollPartSelect {
async _onRender(rollDialog, context, options) { async _onRender(rollDialog, context, options) {
const selectTache = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-tache"]`) const selectTache = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-tache"]`)
const buttonCreate = rollDialog.element.querySelector(`roll-section[name="${this.code}"] button[name="create-tache"]`)
const buttonEdit = rollDialog.element.querySelector(`roll-section[name="${this.code}"] button[name="edit-tache"]`)
selectTache.addEventListener("change", e => { selectTache.addEventListener("change", e => {
const selectOptions = e.currentTarget.options const selectOptions = e.currentTarget.options
@@ -53,14 +57,43 @@ export class RollPartTache extends RollPartSelect {
this.$selectTache(rollDialog.rollData, selectOptions[index]?.value) this.$selectTache(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.render() rollDialog.render()
}) })
buttonCreate?.addEventListener(
"click", async e => {
e.preventDefault()
await rollDialog.rollData.active.actor.createItem(ITEM_TYPES.tache, 'Nouvelle tache')
})
buttonEdit?.addEventListener(
"click", e => {
e.preventDefault()
const current = this.getCurrent(rollDialog.rollData)
current.tache?.sheet.render(true)
})
}
getHooks(rollDialog) {
return [
{ hook: "createItem", fn: (item, options, id) => this.onCreateUpdateItem(rollDialog, item, options, id) },
{ hook: "updateItem", fn: (item, options, id) => this.onCreateUpdateItem(rollDialog, item, options, id) }
]
}
onCreateUpdateItem(rollDialog, item, options, id) {
if (item.type == ITEM_TYPES.tache && item.parent?.id == rollDialog.rollData.active.actor.id) {
this.loadRefs(rollDialog.rollData)
rollDialog.render()
}
} }
impactOtherPart(part, rollData) { impactOtherPart(part, rollData) {
if (this.visible(rollData)) { if (this.visible(rollData)) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
switch (part.code) { if (current.tache) {
case PART_CARAC: return part.filterCaracs(rollData, [current?.tache.system.carac]) switch (part.code) {
case PART_COMP: return part.filterComps(rollData, [current.comp?.name]) case PART_CARAC: return part.filterCaracs(rollData, [current?.tache.system.carac])
case PART_COMP: return part.filterComps(rollData, [current.comp?.name])
}
} }
} }
return undefined return undefined

View File

@@ -15,10 +15,6 @@ export class RollPartTricher extends RollPart {
current.resultat = Misc.inRange(current.resultat == undefined ? -1 : current.resultat, -1, 100) current.resultat = Misc.inRange(current.resultat == undefined ? -1 : current.resultat, -1, 100)
} }
getAjustements(rollData) {
return []
}
async _onRender(rollDialog, context, options) { async _onRender(rollDialog, context, options) {
const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`) const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)

View File

@@ -6,6 +6,8 @@ export const ROLLDIALOG_SECTION = {
CONDITIONS: 'conditions', CONDITIONS: 'conditions',
AJUSTEMENTS: 'ajustements', AJUSTEMENTS: 'ajustements',
} }
export class RollPart { export class RollPart {
static settingKey(rollPart, key) { return `roll-part-${rollPart.code}.${key}` } static settingKey(rollPart, key) { return `roll-part-${rollPart.code}.${key}` }
@@ -104,10 +106,9 @@ export class RollPart {
return { code: this.code, name: this.name, template: this.template, section: this.section } return { code: this.code, name: this.name, template: this.template, section: this.section }
} }
getAjustements(rollData) { getAjustements(rollData) { return [] }
return []
}
async _onRender(rollDialog, context, options) { } async _onRender(rollDialog, context, options) { }
getHooks() { return [] }
} }

View File

@@ -1,5 +1,4 @@
import { DIFF, ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs" import { DIFF, ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs"
import { PART_ATTAQUE } from "./roll-part-attaque.mjs"
import { RollType } from "./roll-type.mjs" import { RollType } from "./roll-type.mjs"
export class RollTypeAttaque extends RollType { export class RollTypeAttaque extends RollType {

View File

@@ -32,17 +32,17 @@ export class RollTypeCuisine extends RollType {
if (current.fabriquer) { if (current.fabriquer) {
const plat = this.$prepareNourriture(rollData.active.name, current, result) const plat = this.$prepareNourriture(rollData.active.name, current, result)
result.messages.push(`${plat.system.quantite} ${plat.name} ont été préparés dans l'équipement`) result.messages.push(`${plat.system.quantite} ${plat.name} ont été préparés dans l'équipement`)
impacts.active.addCreatedItem(plat) impacts.addCreated('Item', plat)
result.plat = { id: plat.id } result.plat = { id: plat.id }
} }
if (current.ingredient) { if (current.ingredient) {
const quantite = Math.min(current.proportions, current.ingredient.system.quantite) const quantite = Math.min(current.proportions, current.ingredient.system.quantite)
if (quantite == current.ingredient.system.quantite) { if (quantite == current.ingredient.system.quantite) {
impacts.active.addDeletedItem(current.ingredient) impacts.addDeleted('Item', current.ingredient)
result.messages.push(`Il n'y a plus de ${ingredient.name}`) result.messages.push(`Il n'y a plus de ${ingredient.name}`)
} }
else { else {
impacts.active.addItemDelta(current.ingredient, 'system.quantite', -current.proportions) impacts.addDelta('Item', current.ingredient, 'system.quantite', -current.proportions)
result.messages.push(`${current.proportions} ${current.ingredient.name} ont été utilisés`) result.messages.push(`${current.proportions} ${current.ingredient.name} ont été utilisés`)
} }
} }
@@ -51,7 +51,7 @@ export class RollTypeCuisine extends RollType {
onApplyImpacts(roll, impacts) { onApplyImpacts(roll, impacts) {
if (roll.result.plat) { if (roll.result.plat) {
// le plat n'est pas créé immédiatement, il faut donc retrouver l'id // le plat n'est pas créé immédiatement, il faut donc retrouver l'id
roll.result.plat.id = impacts.active.itemCreates.find(it => it.id = roll.result.plat.id)?.createdId roll.result.plat.id = impacts.findCreatedId('Item', roll.result.plat.id)
} }
} }

View File

@@ -1,4 +1,5 @@
import { RdDItemSigneDraconique } from "../item/signedraconique.js" import { RdDItemSigneDraconique } from "../item/signedraconique.js"
import { RollBasicParts } from "./roll-basic-parts.mjs"
import { DIFF, ROLL_TYPE_MEDITATION } from "./roll-constants.mjs" import { DIFF, ROLL_TYPE_MEDITATION } from "./roll-constants.mjs"
import { PART_MEDITATION } from "./roll-part-meditation.mjs" import { PART_MEDITATION } from "./roll-part-meditation.mjs"
import { RollType } from "./roll-type.mjs" import { RollType } from "./roll-type.mjs"
@@ -26,7 +27,7 @@ export class RollTypeMeditation extends RollType {
const rolled = rollData.rolled const rolled = rollData.rolled
if (meditation && rolled) { if (meditation && rolled) {
if (rolled.isSuccess) { if (rolled.isSuccess) {
await actor.createEmbeddedDocuments("Item", [RdDItemSigneDraconique.prepareSigneDraconiqueMeditation(meditation, rolled)]) await actor.createEmbeddedDocuments('Item', [RdDItemSigneDraconique.prepareSigneDraconiqueMeditation(meditation, rolled)])
} }
if (rolled.isEPart) { if (rolled.isEPart) {
await actor.updateEmbeddedDocuments('Item', [{ _id: meditation._id, 'system.malus': meditation.system.malus - 1 }]) await actor.updateEmbeddedDocuments('Item', [{ _id: meditation._id, 'system.malus': meditation.system.malus - 1 }])
@@ -34,4 +35,9 @@ export class RollTypeMeditation extends RollType {
await actor.santeIncDec("fatigue", 2) await actor.santeIncDec("fatigue", 2)
} }
} }
async onMonteeTMR(savedRoll, mode){
const actor = RollBasicParts.getTokenActor(savedRoll).actor
return actor?.displayTMR(mode)
}
} }

View File

@@ -1,4 +1,9 @@
import { RdDItemCompetence } from "../item-competence.js"
import { RdDItemSort } from "../item-sort.js"
import { RdDResolutionTable } from "../rdd-resolution-table.js"
import { DIFF, ROLL_TYPE_SORT } from "./roll-constants.mjs" import { DIFF, ROLL_TYPE_SORT } from "./roll-constants.mjs"
import { PART_COMP } from "./roll-part-comp.mjs"
import { PART_SORT } from "./roll-part-sort.mjs"
import { RollType } from "./roll-type.mjs" import { RollType } from "./roll-type.mjs"
export class RollTypeSort extends RollType { export class RollTypeSort extends RollType {
@@ -11,4 +16,69 @@ export class RollTypeSort extends RollType {
onSelect(rollData) { onSelect(rollData) {
this.setDiffType(rollData, DIFF.AUCUN) this.setDiffType(rollData, DIFF.AUCUN)
} }
getResult(rollData, impacts) {
const rolled = rollData.rolled
const actor = rollData.active.actor
const coord = actor.system.reve.tmrpos.coord
const reveActuel = parseInt(actor.system.reve.reve.value)
const draconic = rollData.current[PART_COMP].comp
const current = rollData.current[PART_SORT]
const sort = current.sort
const isReserve = current.isReserve
const reveSort = current.ptreve
const isThanatos = RdDItemCompetence.isThanatos(draconic)
actor.tmrApp?.restoreTMRAfterAction()
current.depenseReve = reveSort
if (isThanatos) { // Si Thanatos
impacts.addActorUpdate("system.reve.reve.thanatosused", true)
}
if (rolled.isSuccess) { // Réussite du sort !
if (rolled.isPart) {
current.depenseReve = Math.max(Math.floor(current.depenseReve / 2), 1)
}
if (isReserve) {
current.depenseReve++
}
if (reveActuel > current.depenseReve) {
// Incrémenter/gére le bonus de case
impacts.addUpdate('Item', sort, 'system.bonuscase', RdDItemSort.calculBonuscase(sort, coord))
if (isReserve) {
impacts.addCreated('Item', RdDItemSort.prepareSortEnReserve(sort, draconic, reveSort, coord))
}
else {
rollData.closeTMR = true
if (sort.system.isrituel) {
impacts.addUpdate('Item', sort, 'system.lancements', RdDItemSort.prepareSortAddLancement(sort, reveSort))
}
}
}
else {
current.depenseReve = 0;
rollData.show.reveInsuffisant = true
foundry.utils.mergeObject(rollData.rolled, RdDResolutionTable.getResultat("echec"), { overwrite: true })
}
} else {
rollData.closeTMR = true
if (rolled.isETotal) { // Echec total !
current.depenseReve = Math.min(reveActuel, Math.floor(current.depenseReve * 1.5))
// TODO: mise en réserve d'un échec total...
} else {
current.depenseReve = 0
}
}
impacts.addActorDelta("system.reve.reve.value", - Math.min(current.depenseReve, reveActuel))
if (current.depenseReve >= reveActuel) { // 0 points de reve
rollData.show.zeroReve = true
}
}
} }

View File

@@ -12,7 +12,7 @@ export class RollTypeTache extends RollType {
title(rollData) { title(rollData) {
const current = rollData.current[PART_TACHE] const current = rollData.current[PART_TACHE]
const tache = current?.tache const tache = current?.tache
return `travaille à sa tâche: ${tache.name ?? ''}` return tache ? `travaille à sa tâche: ${tache.name}` : `n'a pas de tâches à travailler`
} }
onSelect(rollData) { onSelect(rollData) {

View File

@@ -1,15 +1,25 @@
const ACTOR_EMBEDDED_DOCTYPES = ['Item', 'ActiveEffect']
/** /**
* class designed to store actor modification instructions, to apply them in a single operation, and have the ability to revert these * class designed to store actor modification instructions, to apply them in a single operation, and have the ability to revert these
*/ */
export class ActorImpacts { export class ActorImpacts {
static $newDocumentImpacts(docType) {
return { creates: [], deletes: [], updates: [], docType: docType }
}
static $checkDocType(docType) {
if (!ACTOR_EMBEDDED_DOCTYPES.includes(docType)) {
throw `Unsupported document type ${docType}`
}
}
constructor(actorToken) { constructor(actorToken) {
this.actorToken = actorToken this.actorToken = actorToken
this.updates = [] this.updates = []
this.deltas = [] this.deltas = []
this.itemCreates = [] ACTOR_EMBEDDED_DOCTYPES.forEach(
this.itemUpdates = [] docType => this[docType] = ActorImpacts.$newDocumentImpacts(docType)
this.itemDeletes = [] )
} }
addActorUpdate(path, value) { addActorUpdate(path, value) {
@@ -27,46 +37,55 @@ export class ActorImpacts {
} }
} }
addDeletedItem(item) { addDeleted(docType, document) {
this.itemDeletes.push(item) ActorImpacts.$checkDocType(docType)
} this[docType].deletes.push(document)
addCreatedItem(item) {
this.itemCreates.push(item)
} }
addItemUpdate(item, path, value) { addCreated(docType, document) {
const existing = this.itemUpdates.find(it => it.id == item.id) ActorImpacts.$checkDocType(docType)
this[docType].creates.push(document)
}
addUpdate(docType, document, path, value) {
ActorImpacts.$checkDocType(docType)
const update = [path, value] const update = [path, value]
const existing = this[docType].updates.find(it => it.id == document.id)
if (existing) { if (existing) {
existing.updates.push(update) existing.updates.push(update)
} }
else { else {
this.itemUpdates.push({ id: item.id, updates: [update], deltas: [] }) this[docType].updates.push({ id: document.id, updates: [update], deltas: [] })
} }
} }
addItemDelta(item, path, value) { addDelta(document, path, value) {
ActorImpacts.$checkDocType(document)
const intValue = Number.parseInt(value) const intValue = Number.parseInt(value)
if (Number.isInteger(intValue) && intValue != 0) { if (Number.isInteger(intValue) && intValue != 0) {
const delta = [path, intValue] const delta = [path, intValue]
const existing = this.itemUpdates.find(it => it.id == item.id) const existing = this[docType].updates.find(it => it.id == document.id)
if (existing) { if (existing) {
existing.deltas.push(delta) existing.deltas.push(delta)
} }
else { else {
this.itemUpdates.push({ id: item.id, updates: [], deltas: [delta] }) this[docType].updates.push({ id: document.id, updates: [], deltas: [delta] })
} }
} }
else { else {
console.error('Cannot use non integer value {} for delta update', value) console.error('Cannot use non-integer value {} for delta update', value)
} }
} }
reverseImpacts() { reverseImpacts() {
const reverse = ActorImpacts.$computeReverts(new ActorImpacts(this.actorToken), this, __ => this.actorToken.actor) const reverse = ActorImpacts.$computeReverts(new ActorImpacts(this.actorToken), this, __ => this.actorToken.actor)
reverse.itemCreates = this.itemDeletes.map(it => foundry.utils.duplicate(it)) ACTOR_EMBEDDED_DOCTYPES.forEach(
reverse.itemDeletes = this.itemCreates.map(it => { return { id: it.id } }) docType => {
reverse.itemUpdates = this.itemUpdates.map(it => ActorImpacts.$computeReverts({ id: it.id }, it, id => this.$getActorItem(id))) reverse[docType].creates = this[docType].deletes.map(it => foundry.utils.duplicate(it))
reverse[docType].deletes = this[docType].creates.map(it => { return { id: it.id } })
reverse[docType].updates = this[docType].updates.map(it => ActorImpacts.$computeReverts({ id: it.id }, it, id => this.$getEmbeddedDocument(docType, id)))
}
)
return reverse return reverse
} }
@@ -77,40 +96,44 @@ export class ActorImpacts {
async applyImpacts() { async applyImpacts() {
const actor = this.actorToken.actor const actor = this.actorToken.actor
const isItemsDelete = this.itemDeletes.length > 0 await Promise.all(ACTOR_EMBEDDED_DOCTYPES.map(async docType => await this.$applyDocumentsImpacts(actor, docType)))
const isItemsCreate = this.itemCreates.length > 0 const updates = ActorImpacts.$computeUpdates(this, id => actor)
const isItemsUpdate = this.itemUpdates.length > 0 await actor.update(updates, { render: true })
const isActorUpdate = this.updates.length > 0 || this.deltas.length > 0 }
if (isItemsDelete) {
const deletes = this.itemDeletes.map(it => it.id) async $applyDocumentsImpacts(actor, docType) {
await actor.deleteEmbeddedDocuments('Item', deletes, { render: !(isItemsCreate || isItemsUpdate || isActorUpdate) }) if (this[docType].deletes.length > 0) {
const deletes = this[docType].deletes.map(it => it.id)
await actor.deleteEmbeddedDocuments(docType, deletes, { render: false })
} }
if (isItemsCreate) { if (this[docType].creates.length > 0) {
const creates = this.itemCreates const creates = this[docType].creates
const created = await actor.createEmbeddedDocuments('Item', creates, { render: !(isItemsUpdate || isActorUpdate)}) const created = await actor.createEmbeddedDocuments(docType, creates, { render: false })
for (let i=0; i<creates.length; i++){ for (let i = 0; i < creates.length; i++) {
creates[i].createdId = created[i].id creates[i].createdId = created[i].id
} }
} }
if (isItemsUpdate) { if (this[docType].updates.length > 0) {
const updates = this.itemUpdates.map(u => ActorImpacts.$computeUpdates(u, id => this.$getActorItem(id))) const updates = this[docType].updates.map(u => ActorImpacts.$computeUpdates(u, id => this.$getEmbeddedDocument(docType, id)))
await actor.updateEmbeddedDocuments('Item', updates, { render: !isActorUpdate }) await actor.updateEmbeddedDocuments(docType, updates, { render: false })
}
if (isActorUpdate) {
const updates = ActorImpacts.$computeUpdates(this, id => actor)
await actor.update(updates, { render: true })
} }
} }
$getActorItem(id) { findCreatedId(docType, origId){
return this.actorToken.actor.items.get(id) return this[docType].creates.find(it => it.id = origId)?.createdId
}
$getEmbeddedDocument(docType, id) {
return this.actorToken.actor.getEmbeddedDocument(docType, id)
} }
static $computeUpdates(u, getSource) { static $computeUpdates(u, getSource) {
if (u.updates.length == 0 && u.deltas.length == 0) {
return {}
}
const source = getSource(u.id) const source = getSource(u.id)
const instruction = { _id: u.id } const instruction = { _id: u.id }
u.updates.forEach(u => instruction[u[0]] = u[1]) u.updates.forEach(u => instruction[u[0]] = u[1])
@@ -124,5 +147,4 @@ export class ActorImpacts {
target.deltas = u.deltas.map(d => [d[0], -d[1]]) target.deltas = u.deltas.map(d => [d[0], -d[1]])
return target return target
} }
} }

View File

@@ -1,12 +1,12 @@
<form class="app-personnage-aleatoire"> <form class="app-personnage-aleatoire">
<h2>Génération aléatoire pour {{actor.name}}</h2> <h2>{{actor.name}}</h2>
<div class="flex-group-left"> <div class="flex-group-left">
{{#if options.isGM}} {{#if options.isGM}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs" {{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs"
label="Nom" path="name" type="text" value=current.name checked=checked.name label="Nom" path="name" type="text" value=current.name checked=checked.name
}} }}
{{/if}} {{/if}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs" {{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/sexe-aleatoire.hbs"
label="Sexe" path="system.sexe" type="text" label="Sexe" path="system.sexe" type="text"
value=current.system.sexe checked=checked.system.sexe value=current.system.sexe checked=checked.system.sexe
}} }}

View File

@@ -12,8 +12,8 @@
<input class="current-value" name="current.{{path}}" value="{{value}}" placeholder="{{label}}" type="text" data-dtype="String"/> <input class="current-value" name="current.{{path}}" value="{{value}}" placeholder="{{label}}" type="text" data-dtype="String"/>
{{/if}} {{/if}}
<div class="item-controls"> <div class="item-controls">
<input class="check-for-random" type="checkbox" data-tooltip="Sélectionné pour génération automatique" {{#if checked}}checked{{/if}}/>
<a class="random" data-action="random" data-tooltip="Aléatoire"><i class="fa-solid fa-dice-d20"></i></a> <a class="random" data-action="random" data-tooltip="Aléatoire"><i class="fa-solid fa-dice-d20"></i></a>
<a class="reset" data-action="reset" data-tooltip="Reset"><i class="fa-solid fa-eraser"></i></a> <a class="reset" data-action="reset" data-tooltip="Reset"><i class="fa-solid fa-eraser"></i></a>
<input class="check-for-random" type="checkbox" data-tooltip="Sélectionné pour génération automatique" {{#if checked}}checked{{/if}}/>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,11 @@
<div class="flexrow random-field" data-path="{{path}}">
<label for="{{path}}">{{label}}:</label>
<input class="current-value" name="current.{{path}}" value="{{value}}" placeholder="{{label}}" type="text" data-dtype="String"/>
<div class="item-controls">
<input class="check-for-random" type="checkbox" data-tooltip="Sélectionné pour génération automatique" {{#if checked}}checked{{/if}}/>
<a data-action="sexe-feminin" data-tooltip="sexe féminin"><i class="fa-solid fa-venus"></i></a>
<a data-action="sexe-masculin" data-tooltip="sexe masculin"><i class="fa-solid fa-mars"></i></a>
<a class="random" data-action="random" data-tooltip="Aléatoire"><i class="fa-solid fa-dice-d20"></i></a>
<a class="reset" data-action="reset" data-tooltip="Reset"><i class="fa-solid fa-eraser"></i></a>
</div>
</div>

View File

@@ -1,4 +1,3 @@
{{log rolled}}
<div> <div>
<span {{#if ajustements}}class="tooltip-overflow tooltip-dotted" {{/if}}> <span {{#if ajustements}}class="tooltip-overflow tooltip-dotted" {{/if}}>
<span> <span>

View File

@@ -11,7 +11,7 @@
<div class="chat-resume"> <div class="chat-resume">
{{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}}
<br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} <br>{{> 'partial-infojet'}}
</div> </div>
<div class="chat-details"> <div class="chat-details">
@@ -19,18 +19,13 @@
{{#if rolled.isSuccess}} {{#if rolled.isSuccess}}
<span> <span>
<strong>{{opponent.name}}</strong> doit se défendre à <strong>{{current.diff.value}}</strong>, <strong>{{opponent.name}}</strong> doit se défendre à <strong>{{current.diff.value}}</strong>,
{{#if (eq current.dmg.mortalite 'empoignade')}} {{#if (eq dmg.mortalite 'empoignade')}}
ou {{active.name}} marquera un point d'empoignade ou {{active.name}} marquera un point d'empoignade
{{else if (eq current.dmg.mortalite 'non-mortel')}} {{else if (eq dmg.mortalite 'non-mortel')}}
ou encaisser à <span class="rdd-roll-norm">{{plusMoins current.dmg.total}} (non-mortel)</span> ou encaisser à <span class="rdd-roll-norm">{{plusMoins dmg.total}} (non-mortel)</span>
{{else}} {{else}}
{{!-- {{~#if (eq current.dmg.mortalite 'mortel')}} --}} ou encaisser à <span class="rdd-roll-echec">{{plusMoins dmg.total}}</span>
ou encaisser à <span class="rdd-roll-echec">{{plusMoins current.dmg.total}}</span>
{{!-- {{~#if (eq current.dmg.mortalite 'cauchemar')}} --}}
{{!-- {{else}}
<span class="rdd-roll-etotal">{{plusMoins dmg.total}}</span> (entités de cauchemar) --}}
{{/if}} {{/if}}
</span> </span>
{{#if show.recul}} {{#if show.recul}}
<span class='chat-card-info'> <span class='chat-card-info'>
@@ -61,9 +56,11 @@
<p> <p>
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-info-appel-au-moral.hbs"}} {{> "systems/foundryvtt-reve-de-dragon/templates/chat-info-appel-au-moral.hbs"}}
</p> </p>
{{> 'partial-maladresse'}}
</div> </div>
<div class="chat-actions"> <div class="chat-actions">
{{> 'partial-choix-maladresse'}}
{{> 'partial-attaque-particuliere'}} {{> 'partial-attaque-particuliere'}}
{{!-- TODO: maladresses --}} {{!-- TODO: maladresses --}}
</div> </div>

View File

@@ -4,16 +4,16 @@
<img src="{{current.comp.comp.img}}" data-tooltip="{{current.comp.label}}" /> <img src="{{current.comp.comp.img}}" data-tooltip="{{current.comp.label}}" />
</div> </div>
<div class="chat-header"> <div class="chat-header">
{{active.name}} fait un jet de {{current.comp.label}} {{active.name}} fait un jet {{#if (eq current.comp.key '')}}sans compétence{{else}}de {{current.comp.label}}{{/if}}
</div> </div>
<div class="chat-resume"> <div class="chat-resume">
{{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} {{current.carac.label}}{{#unless (eq current.comp.key '')}} / {{current.comp.label}}{{/unless}} à {{current.diff.value}}
<br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} <br>{{> 'partial-infojet'}}
</div> </div>
<div class="chat-details"> <div class="chat-details">
<p>Qualité {{rolled.ptQualite}}, points de tâche {{rolled.ptQualite}} <p>Qualité {{rolled.ptQualite}}, points de tâche {{rolled.ptTache}}
</p> </p>
{{> 'partial-info-appel-moral'}} {{> 'partial-info-appel-moral'}}
</div> </div>

View File

@@ -14,19 +14,19 @@
<div class="chat-resume"> <div class="chat-resume">
{{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}}
<br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} <br>{{> "partial-infojet"}}
</div> </div>
<div class="chat-details"> <div class="chat-details">
<p> <p>
{{active.name}} {{active.name}}
{{#if rolled.isSuccess}} {{#if rolled.isSuccess}}
réussit la recette, pour un plat de qualité {{result.qualite~}} réussit la recette, pour un plat de qualité {{result.qualite}}
{{#if (lt result.exotisme 0)}}et d'exotisme {{result.exotisme}}{{/if~}} {{#if (lt result.exotisme 0)}}et d'exotisme {{result.exotisme}}{{/if}}
{{else}} {{else}}
fait un piètre cuisinier, et obtient un plat de qualité {{result.qualite~}} fait un piètre cuisinier, et obtient un plat de qualité {{result.qualite}}
{{#if (lt result.exotisme 0)}}à l'exotisme certain ({{result.exotisme}}){{/if~}} {{#if (lt result.exotisme 0)}}à l'exotisme certain ({{result.exotisme}}){{/if}}
{{/if~}}. {{~/if~}}.
{{#if (lt result.exotisme 0)}} {{#if (lt result.exotisme 0)}}
<br>Au vu de l'exotisme du plat, les convives devront réussir un jet de @roll[Volonté/Cuisine/{{result.exotisme}}]. <br>Au vu de l'exotisme du plat, les convives devront réussir un jet de @roll[Volonté/Cuisine/{{result.exotisme}}].
En cas d'échec, ils peuvent se forcer à faire plaisir à {{active.name}}, mais devront faire un jet de moral Malheureux. En cas d'échec, ils peuvent se forcer à faire plaisir à {{active.name}}, mais devront faire un jet de moral Malheureux.

View File

@@ -11,7 +11,7 @@
<div class="chat-resume"> <div class="chat-resume">
{{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}}
<br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} <br>{{> 'partial-infojet'}}
</div> </div>
<div class="chat-details"> <div class="chat-details">
@@ -42,9 +42,11 @@
</span> </span>
{{/if}} {{/if}}
{{> 'partial-info-appel-moral'}} {{> 'partial-info-appel-moral'}}
{{> 'partial-maladresse'}}
</div> </div>
<div class="chat-actions"> <div class="chat-actions">
{{!-- TODO: maladresses --}} {{> 'partial-choix-maladresse'}}
{{> 'partial-recul-choc'}} {{> 'partial-recul-choc'}}
{{> 'partial-encaissement'}} {{> 'partial-encaissement'}}
</div> </div>

View File

@@ -9,7 +9,7 @@
<div class="chat-resume"> <div class="chat-resume">
{{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}}
<br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} <br>{{> 'partial-infojet'}}
</div> </div>
<div class="chat-details"> <div class="chat-details">

View File

@@ -9,7 +9,7 @@
<div class="chat-resume"> <div class="chat-resume">
{{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}}
<br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} <br>{{> 'partial-infojet'}}
</div> </div>
<div class="chat-details"> <div class="chat-details">
@@ -39,6 +39,19 @@
{{/if}} {{/if}}
</div> </div>
<div class="chat-actions">
{{#if rolled.isSuccess}}
{{#unless done.meditation}}
<a class='chat-card-button monter-tmr-normale' data-tooltip="Montée rapide dans les TMR" >
<img src="systems/foundryvtt-reve-de-dragon/assets/actions/sort.svg"/>&nbsp;Montée normale dans les TMR
</a>
<a class='chat-card-button monter-tmr-rapide' data-tooltip="Montée rapide dans les TMR" >
<img src="systems/foundryvtt-reve-de-dragon/assets/actions/sort.svg"/>&nbsp;Montée rapide dans les TMR
</a>
{{/unless}}
{{/if}}
</div>
<div class="chat-buttons"> <div class="chat-buttons">
</div> </div>
</div> </div>

View File

@@ -9,7 +9,7 @@
<div class="chat-resume"> <div class="chat-resume">
{{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}}
<br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} <br>{{> 'partial-infojet'}}
</div> </div>
<div class="chat-details"> <div class="chat-details">

View File

@@ -0,0 +1,47 @@
<div class="roll-chat">
<div class="chat-img">
<img src="{{active.img}}" data-tooltip="{{active.name}}" />
<img src="{{current.sort.sort.img}}" data-tooltip="{{current.sort.label}}" />
</div>
<div class="chat-header">
{{active.name}}
{{#if current.sort.isReserve}}met en réserve{{else}}lance{{/if}}
le {{#if current.sort.sort.system.isrituel}}rituel{{else}}sort{{/if}}
{{current.sort.label}}
{{#if (ne current.sort.sort.system.draconic current.comp.comp.name)}}
avec la voie de {{current.comp.comp.name}}
{{/if}}
</div>
<div class="chat-resume">
{{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}}
<br>{{> 'partial-infojet'}}
</div>
<hr>
<div class="chat-details">
<p>
{{#if rolled.isETotal}}Echec TOTAL
{{else if rolled.isEchec}}Echec
{{else}}Réussite{{/if}}
du {{#if current.sort.sort.system.isrituel}}rituel{{else}}sort{{/if}},
{{#if rolled.isSuccess}}
le sort est {{#if current.sort.isReserve}}mis en réserve{{else}}lancé{{/if}}
avec {{current.sort.ptreve}} point{{~#if (gt current.sort.ptreve 1)}}s{{/if}} de rêve en {{caseTmr-label refs.sort.coord}} ({{refs.sort.coord}}).
{{/if}}
</p>
<p>
{{#if (eq current.sort.depenseReve 0)}}Pas de dépense de rêve
{{else if (eq current.sort.depenseReve 1)}}1 point de rêve a été dépensé
{{else}}{{current.sort.depenseReve}} points de rêve ont été dépensés
{{~/if}}.
{{#if show.reveInsuffisant}}Pas assez de rêve!{{/if}}
</p>
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-description.hbs" current.sort.sort.system}}
</div>
<div class="chat-buttons">
</div>
</div>

View File

@@ -9,7 +9,7 @@
<div class="chat-resume"> <div class="chat-resume">
{{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}}
<br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} <br>{{> 'partial-infojet'}}
</div> </div>
<div class="chat-details"> <div class="chat-details">

View File

@@ -0,0 +1,9 @@
{{#if show.maladresse}}
{{#unless maladresse}}
<a class='chat-card-button tirer-maladresse' data-maladresse='{{show.maladresse}}'
data-tooltip="Tirer la maladresse">
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/maladresse.svg"/> Tirer une maladresse
{{#if (eq show.maladresse 'avec-arme')}}armé{{else}}non armé{{/if}}
</a>
{{/unless}}
{{/if}}

View File

@@ -0,0 +1,26 @@
{{#if ajustements}}
<div>
<span class="tooltip-overflow tooltip-dotted" >
<span>
<span>{{rolled.caracValue}} à {{plusMoins rolled.finalLevel}}</span>
<span>= {{rolled.score}}%</span>
{{#if (and rolled.factorHtml (ne rolled.factorHtml 1))}}
<span class="rdd-diviseur">&times;{{{rolled.factorHtml}}}</span>
{{/if}}
</span>
<div class="tooltiptext ttt-ajustements">
{{#each ajustements as |item key|}}
<div class="{{#if item.strong}}strong-text{{/if}}">
{{{item.label}}}{{#if item.value includeZero=true}}: {{plusMoins item.value}}{{/if}}
</div>
{{/each}}
</div>
</span>
</div>
{{/if}}
<div>
<span>{{rolled.roll}} : </span><span class="rdd-roll-{{rolled.code}} strong-text">{{rolled.quality}}</span>
{{#if rolled.ajustementNecessaire}}
<span class="rdd-niveau-requis">(Réussite si {{plusMoins rolled.niveauNecessaire}} / avec niveau {{plusMoins rolled.ajustementNecessaire}}) </span>
{{/if}}
</div>

View File

@@ -0,0 +1,6 @@
{{#if maladresse}}
<span class='chat-card-info'>
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/maladresse.svg"/> Maladresse!
</span>
<div >{{{maladresse}}}</div>
{{/if}}

View File

@@ -2,21 +2,16 @@
<span class="tooltip tooltip-dotted"> <span class="tooltip tooltip-dotted">
<span class="roll-part-resolution">Jet: {{rollData.current.carac.value}} à {{plusMoins rollData.current.totaldiff}}</span> <span class="roll-part-resolution">Jet: {{rollData.current.carac.value}} à {{plusMoins rollData.current.totaldiff}}</span>
<div class="tooltiptext ttt-ajustements"> <div class="tooltiptext ttt-ajustements">
{{#each rollData.ajustements as |ajust|}} {{#each rollData.ajustements as |item|}}
{{#if ajust}}
<div> <div>
{{#if ajust.descr}} {{{item.label}}}{{#if item.value includeZero=true}}: {{plusMoins item.value}}{{/if}}
{{{ajust.descr}}}
{{else}}
{{{ajust.label}}}{{#if ajust.isDiff}}: {{plusMoins ajust.diff}}{{/if}}
{{/if}}
</div> </div>
{{/if}}
{{/each}} {{/each}}
</div> </div>
</span> </span>
{{#if rollData.current.significative.used}} {{#if rollData.current.significative.used}}
<br><span> <br>
<span>
Significative requise <span class="rdd-diviseur">&times;{{{rollData.current.significative.label}}}</span>! Significative requise <span class="rdd-diviseur">&times;{{{rollData.current.significative.label}}}</span>!
</span> </span>
{{/if}} {{/if}}

View File

@@ -7,7 +7,14 @@
{{selectOptions refs.taches selected=current.key valueAttr="key" labelAttr="label"}} {{selectOptions refs.taches selected=current.key valueAttr="key" labelAttr="label"}}
</select> </select>
<selected-numeric-value>{{plusMoins current.value}}</selected-numeric-value> <selected-numeric-value>{{plusMoins current.value}}</selected-numeric-value>
{{#unless refs.forced}}
<button name="create-tache" data-tooltip="Créer une nouvelle tâche"><i class="fa-solid fa-circle-plus"></i></button>
{{#if refs.taches.length}}
<button name="edit-tache" data-tooltip="Modifier la tâche"><i class="fa-solid fa-edit"></i></button>
{{/if}}
{{/unless}}
</subline> </subline>
{{#if refs.taches.length}}
<subline> <subline>
Points de tâche: {{current.tache.system.points_de_tache_courant}} / Points de tâche: {{current.tache.system.points_de_tache_courant}} /
{{#if current.tache.system.cacher_points_de_tache}} {{#if current.tache.system.cacher_points_de_tache}}
@@ -25,4 +32,5 @@
{{#if current.tache.system.periodicite}} {{#if current.tache.system.periodicite}}
<subline>Périodicité: {{current.tache.system.periodicite}}</subline> <subline>Périodicité: {{current.tache.system.periodicite}}</subline>
{{/if}} {{/if}}
{{/if}}
</roll-part-detail> </roll-part-detail>