Nouvelle fenêtre de jets de dés

This commit is contained in:
2025-09-05 01:09:32 +02:00
parent 652c435833
commit 1ff32697f4
134 changed files with 4025 additions and 400 deletions

View File

@@ -19,7 +19,7 @@ import { DialogConsommer } from "./dialog-item-consommer.js";
import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js";
import { RollDataAjustements } from "./rolldata-ajustements.js";
import { RdDPossession } from "./rdd-possession.js";
import { SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { ACTOR_TYPES, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { RdDConfirm } from "./rdd-confirm.js";
import { DialogRepos } from "./sommeil/dialog-repos.js";
import { RdDBaseActor } from "./actor/base-actor.js";
@@ -46,6 +46,8 @@ import { PAS_DE_DRACONIC, POSSESSION_SANS_DRACONIC } from "./item/base-items.js"
import { RdDRollResult } from "./rdd-roll-result.js";
import { RdDInitiative } from "./initiative.mjs";
import RollDialog from "./roll/roll-dialog.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js";
export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre']
@@ -108,7 +110,7 @@ export class RdDActor extends RdDBaseActorSang {
return Number.isNumeric(this.system.compteurs.chance.value) ?
Misc.toInt(this.system.compteurs.chance.value) : this.getChance()
}
getMoralTotal() { return this.system.compteurs.moral?.value ?? 0 }
getMoralTotal() { return parseInt(this.system.compteurs.moral?.value ?? 0) }
getEnduranceMax() { return Math.max(1, Math.max(this.getTaille() + this.getConstitution(), this.getVieMax() + this.getVolonte())) }
@@ -116,8 +118,10 @@ export class RdDActor extends RdDBaseActorSang {
getEtatGeneral(options = { ethylisme: false }) {
const etatGeneral = this.system.compteurs.etat?.value ?? 0
// Pour les jets d'Ethylisme, on retire le malus d'éthylisme (p.162)
const annuleMalusEthylisme = options.ethylisme ? this.malusEthylisme() : 0
return etatGeneral - annuleMalusEthylisme
if (options.ethylisme) {
return etatGeneral - this.malusEthylisme()
}
return etatGeneral
}
/* -------------------------------------------- */
@@ -750,7 +754,7 @@ export class RdDActor extends RdDBaseActorSang {
if (to > Misc.toInt(this.system.reve.seuil.value)) {
updates[`system.reve.seuil.value`] = to; // SFA : Direct and packed changes
//this.setPointsDeSeuil(to);
}
}
}
if (caracName == LIST_CARAC_PERSONNAGE.chance.code) {
if (to > Misc.toInt(this.system.compteurs.chance.value)) {
@@ -972,8 +976,14 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
ethylisme() {
return this.system.compteurs.ethylisme?.value ?? 1;
}
malusEthylisme() {
return Math.min(0, (this.system.compteurs.ethylisme?.value ?? 0));
return Math.min(0, this.ethylisme())
}
isAlcoolise() {
return this.ethylisme() < 1
}
@@ -1559,7 +1569,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
createCallbackAppelAuMoral() { /* Si l'appel au moral est utilisé, on l'affiche dans le chat et on diminue éventuellement le moral */
return {
action: r => this._appliquerAppelMoral(r)
action: r => this.appliquerAppelMoral(r)
};
}
@@ -1655,7 +1665,7 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
async _appliquerAppelMoral(rollData) {
async appliquerAppelMoral(rollData) {
if (!rollData.use.moral || game.settings.get("core", "rollMode") == 'selfroll') {
return
}
@@ -1668,20 +1678,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
$filterSortList(sortList, coord) {
let tmr = TMRUtility.getTMR(coord);
let filtered = []
for (let sort of sortList) {
if (sort.system.caseTMR.toLowerCase().includes('variable')) {
filtered.push(sort);
} else if (sort.system.caseTMRspeciale.toLowerCase().includes('variable')) {
filtered.push(sort);
} else if (sort.system.caseTMR.toLowerCase() == tmr.type) {
filtered.push(sort);
} else if (sort.system.caseTMR.toLowerCase().includes('special') && sort.system.caseTMRspeciale.toLowerCase().includes(coord.toLowerCase())) {
filtered.push(sort);
}
}
return filtered;
return sortList.filter(it => RdDItemSort.isSortOnCoord(it, coord))
}
/* -------------------------------------------- */
@@ -1707,8 +1704,8 @@ export class RdDActor extends RdDBaseActorSang {
ui.notifications.error("Une queue ou un souffle vous empèche de lancer de sort!")
return
}
// Duplication car les pts de reve sont modifiés dans le sort
let sorts = foundry.utils.duplicate(this.$filterSortList(this.itemTypes['sort'], coord));
// Duplication car les pts de reve sont modifiés dans le sort!
let sorts = foundry.utils.duplicate(this.itemTypes[ITEM_TYPES.sort].filter(it => RdDItemSort.isSortOnCoord(it, coord)))
if (sorts.length == 0) {
ui.notifications.info(`Aucun sort disponible en ${TMRUtility.getTMR(coord).label} !`);
return;
@@ -1996,153 +1993,6 @@ export class RdDActor extends RdDBaseActorSang {
}
}
/* -------------------------------------------- */
async _rollArt(artData, selected, oeuvre, callbackAction = async r => await this._resultArt(r)) {
oeuvre.system.niveau = oeuvre.system.niveau ?? 0;
foundry.utils.mergeObject(artData,
{
oeuvre: oeuvre,
art: oeuvre.type,
competence: foundry.utils.duplicate(this.getCompetence(artData.compName ?? oeuvre.system.competence ?? artData.art)),
diffLibre: - oeuvre.system.niveau,
diffConditions: 0,
use: { libre: false, conditions: true, surenc: false },
selectedCarac: foundry.utils.duplicate(this.system.carac[selected])
},
{ overwrite: false });
artData.competence.system.defaut_carac = selected;
if (!artData.forceCarac) {
artData.forceCarac = {};
artData.forceCarac[selected] = foundry.utils.duplicate(this.system.carac[selected]);
}
await this.openRollDialog({
name: `jet-${artData.art}`,
label: `${artData.verbe} ${oeuvre.name}`,
template: `systems/foundryvtt-reve-de-dragon/templates/dialog-roll-${oeuvre.type}.hbs`,
rollData: artData,
callbacks: [{ action: callbackAction }],
})
}
/* -------------------------------------------- */
async _resultArt(artData) {
const niveau = artData.oeuvre.system.niveau ?? 0;
const baseQualite = (artData.rolled.isSuccess ? niveau : artData.competence.system.niveau);
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite;
await RdDRollResult.displayRollData(artData, this.name, `chat-resultat-${artData.art}.hbs`);
}
/* -------------------------------------------- */
async rollChant(id) {
const artData = { art: 'chant', verbe: 'Chanter' };
const oeuvre = foundry.utils.duplicate(this.getChant(id));
await this._rollArt(artData, "ouie", oeuvre);
}
/* -------------------------------------------- */
async rollDanse(id) {
const artData = { art: 'danse', verbe: 'Danser', forceCarac: {} };
const oeuvre = foundry.utils.duplicate(this.findItemLike(id, artData.art));
if (oeuvre.system.agilite) {
artData.forceCarac['agilite'] = foundry.utils.duplicate(this.system.carac.agilite);
}
if (oeuvre.system.apparence) {
artData.forceCarac['apparence'] = foundry.utils.duplicate(this.system.carac.apparence);
}
const selectedCarac = this._getCaracDanse(oeuvre);
await this._rollArt(artData, selectedCarac, oeuvre);
}
/* -------------------------------------------- */
_getCaracDanse(oeuvre) {
if (oeuvre.system.agilite) { return "agilite"; }
else if (oeuvre.system.apparence) { return "apparence"; }
const compData = this.getCompetence(oeuvre.system.competence);
return compData.system.defaut_carac;
}
/* -------------------------------------------- */
async rollMusique(id) {
const artData = { art: 'musique', verbe: 'Jouer' };
const oeuvre = this.findItemLike(id, artData.art);
await this._rollArt(artData, "ouie", oeuvre);
}
/* -------------------------------------------- */
async rollRecetteCuisine(id) {
const oeuvre = this.getRecetteCuisine(id);
const artData = {
verbe: 'Cuisiner',
compName: 'cuisine',
proportions: 1,
ajouterEquipement: false
};
await this._rollArt(artData, 'odoratgout', oeuvre, r => this._resultRecetteCuisine(r));
}
/* -------------------------------------------- */
async _resultRecetteCuisine(cuisine) {
const niveauRecette = cuisine.oeuvre.system.niveau ?? 0;
const baseQualite = (cuisine.rolled.isSuccess ? niveauRecette : cuisine.competence.system.niveau);
cuisine.qualiteFinale = Math.min(baseQualite, niveauRecette) + cuisine.rolled.ptQualite;
cuisine.exotismeFinal = Math.min(Math.min(cuisine.qualiteFinale, cuisine.oeuvre.system.exotisme ?? 0), 0);
cuisine.sust = cuisine.oeuvre.system.sust * Math.min(cuisine.proportions, cuisine.proportionsMax ?? cuisine.proportions)
const platCuisine = {
name: cuisine.oeuvre.name,
type: 'nourritureboisson',
img: 'systems/foundryvtt-reve-de-dragon/icons/objets/provision_cuite.webp',
system: {
"description": cuisine.oeuvre.system.description,
"sust": 1,
"qualite": cuisine.qualiteFinale,
"exotisme": cuisine.exotismeFinal,
"encombrement": 0.1,
"quantite": Math.max(1, Math.floor(cuisine.sust)),
"cout": Math.max(cuisine.qualiteFinale) * 0.01
}
}
if (cuisine.ajouterEquipement) {
await this.createEmbeddedDocuments('Item', [platCuisine]);
ui.notifications.info(`${platCuisine.system.quantite} rations de ${platCuisine.name} ont été ajoutés à votre équipement`);
}
cuisine.platCuisine = platCuisine;
await RdDRollResult.displayRollData(cuisine, this.name, `chat-resultat-${cuisine.art}.hbs`);
}
async preparerNourriture(item) {
if (item.getUtilisationCuisine() == 'brut') {
const nourriture = {
name: 'Plat de ' + item.name,
type: 'recettecuisine',
img: item.img,
system: {
sust: item.system.sust,
exotisme: item.system.exotisme,
ingredients: item.name
}
};
const artData = {
verbe: 'Préparer',
compName: 'cuisine',
proportions: 1,
proportionsMax: Math.min(50, item.system.quantite),
ajouterEquipement: true
};
await this._rollArt(artData, 'odoratgout', nourriture, async (cuisine) => {
await this._resultRecetteCuisine(cuisine);
const remaining = Math.max(item.system.quantite - cuisine.proportions, 0);
if (remaining > 0) {
await item.update({ 'system.quantite': remaining })
}
else {
await this.deleteEmbeddedDocuments('Item', [item.id]);
}
});
}
}
/* -------------------------------------------- */
async rollJeu(id) {
const oeuvre = this.getJeu(id);
@@ -2158,14 +2008,9 @@ export class RdDActor extends RdDBaseActorSang {
listCarac.forEach(c => artData.forceCarac[c] = this.system.carac[c]);
artData.competence.system.niveauReel = artData.competence.system.niveau;
artData.competence.system.niveau = Math.max(artData.competence.system.niveau, oeuvre.system.base);
await this._rollArt(artData, carac, oeuvre);
await this._rollArtV1(artData, carac, oeuvre);
}
async rollOeuvre(id) {
const artData = { art: 'oeuvre', verbe: 'Interpréter' }
const oeuvre = foundry.utils.duplicate(this.findItemLike(id, artData.art))
await this._rollArt(artData, oeuvre.system.default_carac, oeuvre)
}
/* -------------------------------------------- */
async rollMeditation(id) {
@@ -2199,7 +2044,7 @@ export class RdDActor extends RdDBaseActorSang {
if (meditationRoll.rolled.isSuccess) {
await this.createEmbeddedDocuments("Item", [RdDItemSigneDraconique.prepareSigneDraconiqueMeditation(meditationRoll.meditation, meditationRoll.rolled)]);
}
if (meditationRoll.rolled.isEPart){
if (meditationRoll.rolled.isEPart) {
await this.updateEmbeddedDocuments('Item', [{ _id: meditationRoll.meditation._id, 'system.malus': meditationRoll.meditation.system.malus - 1 }]);
}
await this.santeIncDec("fatigue", 2);
@@ -2509,7 +2354,7 @@ export class RdDActor extends RdDBaseActorSang {
this.tmrApp.forceTMRDisplay()
return
}
if (mode != 'visu' && this.getEffect(STATUSES.StatusDemiReve)) {
if (mode != 'visu' && this.isDemiReve()) {
ui.notifications.warn("Les personnage est déjà dans les Terres Médianes, elles s'affichent en visualisation")
mode = "visu"; // bascule le mode en visu automatiquement
}
@@ -2789,8 +2634,11 @@ export class RdDActor extends RdDBaseActorSang {
listeSuivants(filter = suivant => true) {
return RdDActor.$buildSubActorLinks(
this.system.subacteurs.suivants.filter(filter), RdDActor.$transformSubActeurSuivant
)
this.system.subacteurs.suivants, RdDActor.$transformSubActeurSuivant
).filter(filter)
}
listeAmoureux() {
return this.listeSuivants(it => it.coeur > 0 && it.type == ACTOR_TYPES.personnage)
}
getSuivant(subActorId) {
@@ -3200,5 +3048,204 @@ export class RdDActor extends RdDBaseActorSang {
await incarnation.remiseANeuf();
incarnation.sheet.render(true);
}
/* -------------------------------------------- */
async _rollArtV2(oeuvreId, callbackAction = async (actor, rd) => await actor._resultArtV2(rd)) {
const oeuvre = this.items.get(oeuvreId)
const rollData = {
title: `Interpretation de ${oeuvre.name} par ${this.name}`,
mode: {
allowed: ["oeuvre"]
},
selected: {
mode: "oeuvre",
oeuvre: { key: oeuvre.id },
},
ids: {
actorId: this.id
}
}
await RollDialog.create(rollData, {
onRoll: (dialog) => {
this._onCloseRollDialog(),
dialog.close()
},
customChatMessage: true,
callbacks: [callbackAction]
})
}
async _resultArtV2(artData) {
const niveau = artData.oeuvre.system.niveau ?? 0;
const baseQualite = (artData.rolled.isSuccess ? niveau : artData.competence.system.niveau);
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite;
await RdDRollResult.displayRollData(artData, this.name, `chat-resultat-${artData.art}.hbs`);
}
/* -------------------------------------------- */
async rollOeuvre(id) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
return await this._rollArtV2(id)
}
else {
const artData = { art: 'oeuvre', verbe: 'Interpréter' }
const oeuvre = foundry.utils.duplicate(this.findItemLike(id, artData.art))
await this._rollArtV1(artData, oeuvre.system.default_carac, oeuvre)
}
}
async rollChant(id) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
await this._rollArtV2(id)
}
else {
const artData = { art: 'chant', verbe: 'Chanter' }
const oeuvre = foundry.utils.duplicate(this.getChant(id))
await this._rollArtV1(artData, "ouie", oeuvre)
}
}
async rollDanse(id) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
await this._rollArtV2(id)
}
else {
const artData = { art: 'danse', verbe: 'Danser', forceCarac: {} }
const oeuvre = foundry.utils.duplicate(this.findItemLike(id, artData.art))
let selectedCarac = this.getCompetence(oeuvre.system.competence)?.system.defaut_carac
if (oeuvre.system.apparence) {
artData.forceCarac['apparence'] = foundry.utils.duplicate(this.system.carac.apparence)
selectedCarac = "apparence"
}
if (oeuvre.system.agilite) {
artData.forceCarac['agilite'] = foundry.utils.duplicate(this.system.carac.agilite)
selectedCarac = "agilite"
}
await this._rollArtV1(artData, selectedCarac, oeuvre)
}
}
async rollMusique(id) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
await this._rollArtV2(id)
}
else {
const artData = { art: 'musique', verbe: 'Jouer' }
const oeuvre = this.findItemLike(id, artData.art)
await this._rollArtV1(artData, "ouie", oeuvre)
}
}
/* -------------------------------------------- */
async _rollArtV1(artData, selected, oeuvre, callbackAction = async r => await this._resultArt(r)) {
oeuvre.system.niveau = oeuvre.system.niveau ?? 0;
foundry.utils.mergeObject(artData,
{
oeuvre: oeuvre,
art: oeuvre.type,
competence: foundry.utils.duplicate(this.getCompetence(artData.compName ?? oeuvre.system.competence ?? artData.art)),
diffLibre: - oeuvre.system.niveau,
diffConditions: 0,
use: { libre: false, conditions: true, surenc: false },
selectedCarac: foundry.utils.duplicate(this.system.carac[selected])
},
{ overwrite: false });
artData.competence.system.defaut_carac = selected;
if (!artData.forceCarac) {
artData.forceCarac = {};
artData.forceCarac[selected] = foundry.utils.duplicate(this.system.carac[selected]);
}
await this.openRollDialog({
name: `jet-${artData.art}`,
label: `${artData.verbe} ${oeuvre.name}`,
template: `systems/foundryvtt-reve-de-dragon/templates/dialog-roll-${oeuvre.type}.hbs`,
rollData: artData,
callbacks: [{ action: callbackAction }],
})
}
async _resultArt(artData) {
const niveau = artData.oeuvre.system.niveau ?? 0;
const baseQualite = (artData.rolled.isSuccess ? niveau : artData.competence.system.niveau);
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite;
await RdDRollResult.displayRollData(artData, this.name, `chat-resultat-${artData.art}.hbs`);
}
/* -------------------------------------------- */
async rollRecetteCuisine(id) {
const oeuvre = this.getRecetteCuisine(id);
const artData = {
verbe: 'Cuisiner',
compName: 'cuisine',
proportions: 1,
ajouterEquipement: false
};
await this._rollArtV1(artData, 'odoratgout', oeuvre, r => this._resultRecetteCuisine(r));
}
/* -------------------------------------------- */
async _resultRecetteCuisine(cuisine) {
const niveauRecette = cuisine.oeuvre.system.niveau ?? 0;
const baseQualite = (cuisine.rolled.isSuccess ? niveauRecette : cuisine.competence.system.niveau);
cuisine.qualiteFinale = Math.min(baseQualite, niveauRecette) + cuisine.rolled.ptQualite;
cuisine.exotismeFinal = Math.min(Math.min(cuisine.qualiteFinale, cuisine.oeuvre.system.exotisme ?? 0), 0);
cuisine.sust = cuisine.oeuvre.system.sust * Math.min(cuisine.proportions, cuisine.proportionsMax ?? cuisine.proportions)
const platCuisine = {
name: cuisine.oeuvre.name,
type: 'nourritureboisson',
img: 'systems/foundryvtt-reve-de-dragon/icons/objets/provision_cuite.webp',
system: {
"description": cuisine.oeuvre.system.description,
"sust": 1,
"qualite": cuisine.qualiteFinale,
"exotisme": cuisine.exotismeFinal,
"encombrement": 0.1,
"quantite": Math.max(1, Math.floor(cuisine.sust)),
"cout": Math.max(cuisine.qualiteFinale) * 0.01
}
}
if (cuisine.ajouterEquipement) {
await this.createEmbeddedDocuments('Item', [platCuisine]);
ui.notifications.info(`${platCuisine.system.quantite} rations de ${platCuisine.name} ont été ajoutés à votre équipement`);
}
cuisine.platCuisine = platCuisine;
await RdDRollResult.displayRollData(cuisine, this.name, `chat-resultat-${cuisine.art}.hbs`);
}
async preparerNourriture(item) {
if (item.getUtilisationCuisine() == 'brut') {
const nourriture = {
name: 'Plat de ' + item.name,
type: 'recettecuisine',
img: item.img,
system: {
sust: item.system.sust,
exotisme: item.system.exotisme,
ingredients: item.name
}
};
const artData = {
verbe: 'Préparer',
compName: 'cuisine',
proportions: 1,
proportionsMax: Math.min(50, item.system.quantite),
ajouterEquipement: true
};
await this._rollArtV1(artData, 'odoratgout', nourriture, async (cuisine) => {
await this._resultRecetteCuisine(cuisine);
const remaining = Math.max(item.system.quantite - cuisine.proportions, 0);
if (remaining > 0) {
await item.update({ 'system.quantite': remaining })
}
else {
await this.deleteEmbeddedDocuments('Item', [item.id]);
}
});
}
}
}