Merge branch 'master-fixes' into 'master'

Fix: recalcul des nombres astraux

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!172
This commit is contained in:
Leratier Bretonnien 2021-03-20 17:42:29 +00:00
commit 2b6d1d8de1
13 changed files with 253 additions and 233 deletions

View File

@ -26,6 +26,7 @@ import { Poetique } from "./poetique.js";
import { EffetsDraconiques } from "./tmr/effets-draconiques.js"; import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
import { Draconique } from "./tmr/draconique.js"; import { Draconique } from "./tmr/draconique.js";
import { RdDCarac } from "./rdd-carac.js"; import { RdDCarac } from "./rdd-carac.js";
import { Monnaie } from "./item-monnaie.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -56,36 +57,25 @@ export class RdDActor extends Actor {
*/ */
static async create(data, options) { static async create(data, options) {
// Case of compendium global import // Case of compendium global import
if (data instanceof Array) { if (data instanceof Array) {
return super.create(data, options); return super.create(data, options);
} }
const isPersonnage = data.type == "personnage";
// If the created actor has items (only applicable to duplicated actors) bypass the new actor creation logic // If the created actor has items (only applicable to duplicated actors) bypass the new actor creation logic
if (data.items) { if (data.items) {
let actor = super.create(data, options); let actor = super.create(data, options);
if (data.type == "personnage") { if (isPersonnage) {
await actor.checkMonnaiePresence(data.items); await actor.checkMonnaiePresence(data.items);
} }
return actor; return actor;
} }
let compendiumName; data.items = await RdDUtility.loadCompendium(RdDItemCompetence.actorCompendium(data.type));
if (data.type == "personnage") { if (isPersonnage) {
compendiumName = "foundryvtt-reve-de-dragon.competences"; data.items = data.items.concat(Monnaie.monnaiesData());
} else if (data.type == "creature") {
compendiumName = "foundryvtt-reve-de-dragon.competences-creatures";
} else if (data.type == "entite") {
compendiumName = "foundryvtt-reve-de-dragon.competences-entites";
} }
if (compendiumName) {
data.items = await RdDUtility.loadCompendium(compendiumName);
}
// Ajout monnaie
if (data.type == "personnage" && data.items) {
await RdDActor.ajouterMonnaie(data.items);
}
return super.create(data, options); return super.create(data, options);
} }
@ -151,41 +141,10 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async checkMonnaiePresence(items) { // Ajout opportuniste si les pièces n'existent pas. async checkMonnaiePresence(items) { // Ajout opportuniste si les pièces n'existent pas.
if (!items) return; // Sanity check during import if (!items) return; // Sanity check during import
let piece = items.find(item => item.type == 'monnaie' && Number(item.data.valeur_deniers) == 1); let manquantes = Monnaie.monnaiesManquantes(items);
let newMonnaie = []; if (manquantes.length > 0) {
if (!piece) { await this.createOwnedItem(manquantes);
newMonnaie.push(RdDUtility.createMonnaie("Etain (1 denier)", 1, "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp"));
} }
piece = items.find(item => item.type == 'monnaie' && Number(item.data.valeur_deniers) == 10);
if (!piece) {
newMonnaie.push(RdDUtility.createMonnaie("Bronze (10 deniers)", 10, "systems/foundryvtt-reve-de-dragon/icons/objets/piece_bronze_epees.webp"));
}
piece = items.find(item => item.type == 'monnaie' && Number(item.data.valeur_deniers) == 100);
if (!piece) {
newMonnaie.push(RdDUtility.createMonnaie("Argent (1 sol)", 100, "systems/foundryvtt-reve-de-dragon/icons/objets/piece_argent_sol.webp"));
}
piece = items.find(item => item.type == 'monnaie' && Number(item.data.valeur_deniers) == 1000);
if (!piece) {
newMonnaie.push(RdDUtility.createMonnaie("Or (10 sols)", 1000, "systems/foundryvtt-reve-de-dragon/icons/objets/piece_or_sol.webp"));
}
if (newMonnaie.length > 0) {
await this.createOwnedItem(newMonnaie);
}
}
/* -------------------------------------------- */
static async ajouterMonnaie(items) { // Creation auto à la création du personnage
let etain = RdDUtility.createMonnaie("Etain (1 denier)", 1, "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp");
items.push(etain);
let bronze = RdDUtility.createMonnaie("Bronze (10 deniers)", 10, "systems/foundryvtt-reve-de-dragon/icons/objets/piece_bronze_epees.webp");
items.push(bronze);
let argent = RdDUtility.createMonnaie("Argent (1 sol)", 100, "systems/foundryvtt-reve-de-dragon/icons/objets/piece_argent_sol.webp");
items.push(argent);
let or = RdDUtility.createMonnaie("Or (10 sols)", 1000, "systems/foundryvtt-reve-de-dragon/icons/objets/piece_or_sol.webp");
items.push(or);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -307,7 +266,7 @@ export class RdDActor extends Actor {
getBestDraconic() { getBestDraconic() {
const list = this.getDraconicList().sort((a, b) => b.data.niveau - a.data.niveau); const list = this.getDraconicList().sort((a, b) => b.data.niveau - a.data.niveau);
if (list.length == 0) { if (list.length == 0) {
return { name: "none", data: { niveau: -11 } }; return { name: "Aucun", data: { niveau: -11 } };
} }
return duplicate(list[0]); return duplicate(list[0]);
} }
@ -350,27 +309,30 @@ export class RdDActor extends Actor {
}; };
const blessures = duplicate(this.data.data.blessures); const blessures = duplicate(this.data.data.blessures);
console.log("dormirChateauDormant", blessures)
await this._recupererBlessures(message, "legere", blessures.legeres.liste.filter(b => b.active), []); await this._recupererBlessures(message, "legere", blessures.legeres.liste.filter(b => b.active), []);
await this._recupererBlessures(message, "grave", blessures.graves.liste.filter(b => b.active), blessures.legeres.liste); await this._recupererBlessures(message, "grave", blessures.graves.liste.filter(b => b.active), blessures.legeres.liste);
await this._recupererBlessures(message, "critique", blessures.critiques.liste.filter(b => b.active), blessures.graves.liste); await this._recupererBlessures(message, "critique", blessures.critiques.liste.filter(b => b.active), blessures.graves.liste);
await this.update({ "data.blessures": blessures }); await this.update({ "data.blessures": blessures });
await this._recupererVie(message); await this._recupererVie(message);
await this.jetDeMoral('neutre'); await this.jetDeMoral('neutre');
await this._recupereChance();
// On ne récupère un point de chance que si aucun appel à la chance dans la journée await this.transformerStress();
let utilisationChance = duplicate(this.getFlag('foundryvtt-reve-de-dragon', 'utilisationChance') ?? false);
if (!utilisationChance) {
await this.chanceActuelleIncDec(1);
}
await this.unsetFlag('foundryvtt-reve-de-dragon', 'utilisationChance'); // Nouveau jour, suppression du flag
this.transformerStress();
await this.retourSeuilDeReve(message); await this.retourSeuilDeReve(message);
message.content = `A la fin Chateau Dormant, ${message.content}<br>Un nouveau jour se lève`; message.content = `A la fin Chateau Dormant, ${message.content}<br>Un nouveau jour se lève`;
ChatMessage.create(message); ChatMessage.create(message);
} }
async _recupereChance() {
// On ne récupère un point de chance que si aucun appel à la chance dans la journée
if (this.getFlag('foundryvtt-reve-de-dragon', 'utilisationChance')) {
// Nouveau jour, suppression du flag
await this.unsetFlag('foundryvtt-reve-de-dragon', 'utilisationChance');
}
else {
await this.chanceActuelleIncDec(1);
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async _recupererBlessures(message, type, liste, moindres) { async _recupererBlessures(message, type, liste, moindres) {
let count = 0; let count = 0;
@ -480,9 +442,7 @@ export class RdDActor extends Actor {
await this.santeIncDec("vie", this.data.data.sante.vie.max - this.data.data.sante.vie.value); await this.santeIncDec("vie", this.data.data.sante.vie.max - this.data.data.sante.vie.value);
await this.santeIncDec("endurance", this.data.data.sante.endurance.max - this.data.data.sante.endurance.value); await this.santeIncDec("endurance", this.data.data.sante.endurance.max - this.data.data.sante.endurance.value);
if (this.data.data.sante.fatigue) { if (this.data.data.sante.fatigue) {
let fatigue = duplicate(this.data.data.sante.fatigue) await this.update({ "data.sante.fatigue.value": 0 });
fatigue.value = 0;
await this.update({ "data.sante.fatigue": fatigue });
} }
} }
ChatMessage.create(message); ChatMessage.create(message);
@ -532,16 +492,16 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async recupererFatigue(message) { async recupererFatigue(message) {
let fatigue = duplicate(this.data.data.sante.fatigue) let fatigue = this.data.data.sante.fatigue.value;
const fatigueMin = this._computeFatigueMin(); const fatigueMin = this._computeFatigueMin();
if (fatigue.value <= fatigueMin) { if (fatigue <= fatigueMin) {
message.content += "Vous êtes déjà reposé. "; message.content += "Vous êtes déjà reposé. ";
return; return;
} }
fatigue.value = Math.max(fatigueMin, this._calculRecuperationSegment(fatigue.value)); fatigue = Math.max(fatigueMin, this._calculRecuperationSegment(fatigue));
console.log("recupererFatigue", fatigue) console.log("recupererFatigue", fatigue)
await this.update({ "data.sante.fatigue": fatigue }); await this.update({ "data.sante.fatigue.value": fatigue });
if (fatigue.value == 0) { if (fatigue == 0) {
message.content += "Vous êtes complêtement reposé. "; message.content += "Vous êtes complêtement reposé. ";
} }
} }
@ -680,9 +640,9 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async sortMisEnReserve(rollData, sort) { async sortMisEnReserve(rollData, sort) {
let reserve = duplicate(this.data.data.reve.reserve); let reserve = duplicate(this.data.data.reve.reserve.list);
reserve.list.push({ coord: rollData.tmr.coord, sort: sort, draconic: duplicate(rollData.competence) }); reserve.push({ coord: rollData.tmr.coord, sort: sort, draconic: duplicate(rollData.competence) });
await this.update({ "data.reve.reserve": reserve }); await this.update({ "data.reve.reserve.list": reserve });
this.currentTMR.updateTokens(); this.currentTMR.updateTokens();
} }
@ -752,7 +712,7 @@ export class RdDActor extends Actor {
}); });
} }
const update = { _id: comp._id, 'data.niveau': nouveauNiveau }; const update = { _id: comp._id, 'data.niveau': nouveauNiveau };
const updated = await this.updateEmbeddedEntity("OwnedItem", update); // Updates one EmbeddedEntity await this.updateEmbeddedEntity("OwnedItem", update); // Updates one EmbeddedEntity
} else { } else {
console.log("Competence not found", compName); console.log("Competence not found", compName);
} }
@ -765,7 +725,7 @@ export class RdDActor extends Actor {
compValue = compValue ?? 0; compValue = compValue ?? 0;
this.checkCompetenceXP(compName, compValue); this.checkCompetenceXP(compName, compValue);
const update = { _id: comp._id, 'data.xp': compValue }; const update = { _id: comp._id, 'data.xp': compValue };
const updated = await this.updateEmbeddedEntity("OwnedItem", update); // Updates one EmbeddedEntity await this.updateEmbeddedEntity("OwnedItem", update); // Updates one EmbeddedEntity
} else { } else {
console.log("Competence not found", compName); console.log("Competence not found", compName);
} }
@ -778,7 +738,7 @@ export class RdDActor extends Actor {
if (comp) { if (comp) {
compValue = compValue ?? 0; compValue = compValue ?? 0;
const update = { _id: comp._id, 'data.xp_sort': compValue }; const update = { _id: comp._id, 'data.xp_sort': compValue };
const updated = await this.updateEmbeddedEntity("OwnedItem", update); // Updates one EmbeddedEntity await this.updateEmbeddedEntity("OwnedItem", update); // Updates one EmbeddedEntity
} else { } else {
console.log("Competence not found", compName); console.log("Competence not found", compName);
} }
@ -790,7 +750,7 @@ export class RdDActor extends Actor {
if (comp) { if (comp) {
compValue = compValue ?? 0; compValue = compValue ?? 0;
const update = { _id: comp._id, 'data.niveau_archetype': compValue }; const update = { _id: comp._id, 'data.niveau_archetype': compValue };
const updated = await this.updateEmbeddedEntity("OwnedItem", update); // Updates one EmbeddedEntity await this.updateEmbeddedEntity("OwnedItem", update); // Updates one EmbeddedEntity
} else { } else {
console.log("Competence not found", compName); console.log("Competence not found", compName);
} }
@ -798,7 +758,6 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async updateCompteurValue(fieldName, fieldValue) { async updateCompteurValue(fieldName, fieldValue) {
//console.log("Update", fieldName, fieldValue);
let compteurs = duplicate(this.data.data.compteurs); let compteurs = duplicate(this.data.data.compteurs);
compteurs[fieldName].value = fieldValue; compteurs[fieldName].value = fieldValue;
await this.update({ "data.compteurs": compteurs }); await this.update({ "data.compteurs": compteurs });
@ -992,8 +951,6 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async computeEncombrementTotalEtMalusArmure() { async computeEncombrementTotalEtMalusArmure() {
let encTotal = 0; let encTotal = 0;
let malusArmureData = (this.data.data.attributs && this.data.data.attributs.malusarmure) ? duplicate(this.data.data.attributs.malusarmure) : {};
let newMalusArmure = 0; let newMalusArmure = 0;
for (const item of this.data.items) { for (const item of this.data.items) {
if (item.type == 'armure' && item.data.equipe) { // Armure équipée, intégration du malus armure total if (item.type == 'armure' && item.data.equipe) { // Armure équipée, intégration du malus armure total
@ -1014,10 +971,10 @@ export class RdDActor extends Actor {
// Mise à jour valeur totale et états // Mise à jour valeur totale et états
this.encTotal = encTotal; this.encTotal = encTotal;
this.detectSurEncombrement(); this.detectSurEncombrement();
// Mise à jour éventuelle du malus armure // Mise à jour éventuelle du malus armure
if (this.data.data.attributs && this.data.data.attributs.malusarmure && newMalusArmure != malusArmureData.value) { if (this.data.data.attributs?.malusarmure && newMalusArmure != this.data.data.attributs.malusarmure.value) {
malusArmureData.value = newMalusArmure; await this.update({ "data.attributs.malusarmure.value ": newMalusArmure });
await this.update({ "data.attributs.malusarmure": malusArmureData });
} }
return this.encTotal; return this.encTotal;
} }
@ -1049,12 +1006,12 @@ export class RdDActor extends Actor {
let resume = "Blessures:"; let resume = "Blessures:";
if (nbCritiques > 0 || nbGraves > 0 || nbLegeres > 0) { if (nbCritiques > 0 || nbGraves > 0 || nbLegeres > 0) {
if (nbLegeres > 0) { if (nbLegeres > 0) {
resume += " " + nbLegeres + " légères"; resume += " " + nbLegeres + " légère" + (nbLegeres > 1 ? "s" : "");
} }
if (nbGraves > 0) { if (nbGraves > 0) {
if (nbLegeres > 0) if (nbLegeres > 0)
resume += ","; resume += ",";
resume += " " + nbGraves + " graves"; resume += " " + nbGraves + " grave" + (nbGraves > 1 ? "s" : "");
} }
if (nbCritiques > 0) { if (nbCritiques > 0) {
if (nbGraves > 0 || nbLegeres > 0) if (nbGraves > 0 || nbLegeres > 0)
@ -1063,7 +1020,7 @@ export class RdDActor extends Actor {
} }
} }
else { else {
resume += " aucune"; resume = "Aucune blessure";
} }
return resume; return resume;
} }
@ -1093,20 +1050,14 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async ajouterRefoulement(value = 1) { async ajouterRefoulement(value = 1) {
let ret = "none"; let refoulement = this.data.data.reve.refoulement.value + value;
let refoulement = duplicate(this.data.data.reve.refoulement);
refoulement.value = refoulement.value + value;
let total = new Roll("1d20").roll().total; let total = new Roll("1d20").roll().total;
if (total <= refoulement.value) { if (total <= refoulement) {
refoulement.value = 0; refoulement = 0;
this.ajouterSouffle({ chat: true }); await this.ajouterSouffle({ chat: true });
ret = "souffle";
} }
await this.update({ "data.reve.refoulement.value": refoulement });
await this.update({ "data.reve.refoulement": refoulement }); return refoulement == 0 ? "souffle" : "none";
return ret;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -1119,7 +1070,6 @@ export class RdDActor extends Actor {
content: this.name + " subit un Souffle de Dragon : " + souffle.name content: this.name + " subit un Souffle de Dragon : " + souffle.name
}); });
} }
// TODO: fermeture cité
return souffle; return souffle;
} }
@ -1128,9 +1078,7 @@ export class RdDActor extends Actor {
let queue; let queue;
if (this.data.data.reve.reve.thanatosused) { if (this.data.data.reve.reve.thanatosused) {
queue = await RdDRollTables.getOmbre(); queue = await RdDRollTables.getOmbre();
let myReve = duplicate(this.data.data.reve.reve); await this.update({ "data.reve.reve.thanatosused": false });
myReve.thanatosused = false;
await this.update({ "data.reve.reve": myReve });
} }
else { else {
queue = await RdDRollTables.getQueue(); queue = await RdDRollTables.getQueue();
@ -1165,40 +1113,25 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
getTMRRencontres() { getTMRRencontres() {
return this.data.data.reve.rencontre; return this.data.data.reve.rencontre.list;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async deleteTMRRencontreAtPosition() { async deleteTMRRencontreAtPosition() {
let rencontres = duplicate(this.getTMRRencontres()); let rencontres = this.getTMRRencontres();
let len = rencontres.list.length; let newRencontres = rencontres.filter(it => it.coord != this.getDemiReve());
let i = 0; if (newRencontres.length != rencontres.length) {
//console.log("List", rencontres, len); await this.update({ "data.reve.rencontre.list": newRencontres });
let newTable = [];
for (i = 0; i < len; i++) {
if (rencontres.list[i].coord != this.getDemiReve())
newTable.push(rencontres.list[i]);
}
if (newTable.length != len) {
rencontres.list = newTable;
//console.log("Result: ", rencontres);
await this.update({ "data.reve.rencontre": rencontres });
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async addTMRRencontre(currentRencontre) { async addTMRRencontre(currentRencontre) {
let rencontres = duplicate(this.getTMRRencontres()); let rencontres = this.getTMRRencontres();
let len = rencontres.list.length; let newRencontres = rencontres.filter(it => it.coord != this.getDemiReve());
let i = 0; if (newRencontres.length == rencontres.length) {
let already = false; newRencontres.push(currentRencontre);
for (i = 0; i < len; i++) { await this.update({ "data.reve.rencontre": newRencontres });
if (rencontres.list[i].coord == this.getDemiReve())
already = true;
}
if (!already) {
rencontres.list.push(currentRencontre);
await this.update({ "data.reve.rencontre": rencontres });
} }
} }
@ -1220,9 +1153,8 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async reveActuelIncDec(value) { async reveActuelIncDec(value) {
let reve = duplicate(this.data.data.reve.reve); let reve = Math.max(this.data.data.reve.reve.value + value, 0);
reve.value = Math.max(reve.value + value, 0); await this.update({ "data.reve.reve.value": reve });
await this.update({ "data.reve.reve": reve });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -1235,17 +1167,13 @@ export class RdDActor extends Actor {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async setPointsDeSeuil(value) { async setPointsDeSeuil(seuil) {
let seuil = duplicate(this.data.data.reve.seuil); await this.update({ "data.reve.seuil.value": seuil });
seuil.value = value;
await this.update({ "data.reve.seuil": seuil });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async setPointsDeChance(value) { async setPointsDeChance(chance) {
let chance = duplicate(this.data.data.compteurs.chance); await this.update({ "data.compteurs.chance.value": chance });
chance.value = value;
await this.update({ "data.compteurs.chance": chance });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -1299,7 +1227,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async testSiSonne(sante, endurance) { async testSiSonne(sante, endurance) {
const roll = new Roll("1d20").roll(); const roll = new Roll("1d20").evaluate();
roll.showDice = true; roll.showDice = true;
RdDDice.show(roll); RdDDice.show(roll);
let result = { let result = {
@ -1307,18 +1235,20 @@ export class RdDActor extends Actor {
sonne: roll.total > endurance || roll.total == 20 // 20 is always a failure sonne: roll.total > endurance || roll.total == 20 // 20 is always a failure
} }
if (roll.total == 1) { if (roll.total == 1) {
let xp = Misc.toInt(this.data.data.carac.constitution.xp) + 1; await this.ajoutXpConstitution(1); // +1 XP !
this.update({ "data.carac.constitution.xp": xp }); // +1 XP !
ChatMessage.create({ content: `${this.name} a obenu 1 sur son Jet d'Endurance et a gagné 1 point d'Expérience en Constitution. Ce point d'XP a été ajouté automatiquement).` }); ChatMessage.create({ content: `${this.name} a obenu 1 sur son Jet d'Endurance et a gagné 1 point d'Expérience en Constitution. Ce point d'XP a été ajouté automatiquement).` });
} }
if (result.sonne) { if (result.sonne) {
await this.setSonne(); await this.setSonne();
sante.sonne.value = true; sante.sonne.value = true;
} }
return result; return result;
} }
async ajoutXpConstitution(xp) {
await this.update({ "data.carac.constitution.xp": Misc.toInt(this.data.data.carac.constitution.xp) + xp });
}
/* -------------------------------------------- */ /* -------------------------------------------- */
countBlessures(blessuresListe) { countBlessures(blessuresListe) {
return blessuresListe.filter(b => b.active).length return blessuresListe.filter(b => b.active).length
@ -1338,14 +1268,12 @@ export class RdDActor extends Actor {
if (myRoll.total == 1 || (myRoll.total != 20 && myRoll.total <= this.data.data.sante.endurance.value)) { if (myRoll.total == 1 || (myRoll.total != 20 && myRoll.total <= this.data.data.sante.endurance.value)) {
msgText += `${this.name} a réussi son Jet d'Endurance !`; msgText += `${this.name} a réussi son Jet d'Endurance !`;
if (myRoll.total == 1) { if (myRoll.total == 1) {
await this.ajoutXpConstitution();
msgText += `et gagne 1 Point d'Experience en Constitution`; msgText += `et gagne 1 Point d'Experience en Constitution`;
let constit = duplicate(this.data.data.carac.constitution)
constit.xp += 1;
await this.update({ "data.carac.constitution": constit });
} }
} else { } else {
msgText += `${this.name} a échoué son Jet d'Endurance et devient Sonné`;
await this.setSonne(); await this.setSonne();
msgText += `${this.name} a échoué son Jet d'Endurance et devient Sonné`;
} }
const message = { const message = {
content: msgText, content: msgText,
@ -1454,29 +1382,25 @@ export class RdDActor extends Actor {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async manageBlessureFromSheet(bType, index, active) { async manageBlessureFromSheet(gravite, index) {
let bList = duplicate(this.data.data.blessures); let listBlessures = duplicate(this.data.data.blessures);
let blessure = bList[bType + "s"].liste[index]; let blessure = listBlessures[gravite + "s"].liste[index];
blessure.active = !blessure.active; blessure.active = !blessure.active;
if (!blessure.active) { if (!blessure.active) {
blessure.premiers_soins = 0; this._supprimerBlessure(blessure);
blessure.soins_complets = 0;
blessure.jours = 0;
blessure.loc = "";
} }
//console.log("Blessure update", bType, index, blessure, bList ); await this.update({ 'data.blessures': listBlessures });
await this.update({ 'data.blessures': bList });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async setDataBlessureFromSheet(bType, index, psoins, pcomplets, jours, loc) { async setDataBlessureFromSheet(gravite, index, psoins, pcomplets, jours, loc) {
let bList = duplicate(this.data.data.blessures); let listBlessures = duplicate(this.data.data.blessures);
let blessure = bList[bType + "s"].liste[index]; let blessure = listBlessures[gravite + "s"].liste[index];
blessure.premiers_soins = psoins; blessure.premiers_soins = psoins;
blessure.soins_complets = pcomplets; blessure.soins_complets = pcomplets;
blessure.jours = jours; blessure.jours = jours;
blessure.loc = loc; blessure.loc = loc;
await this.update({ 'data.blessures': bList }); await this.update({ 'data.blessures': listBlessures });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -1499,24 +1423,21 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async moralIncDec(ajustementMoral) { async moralIncDec(ajustementMoral) {
let compteurs = duplicate(this.data.data.compteurs);
compteurs.moral.value = Misc.toInt(compteurs.moral.value);;
if (ajustementMoral != 0) { if (ajustementMoral != 0) {
compteurs.moral.value += ajustementMoral; let moral = Misc.toInt(this.data.data.compteurs.moral.value) + ajustementMoral
if (compteurs.moral.value > 3) { if (moral > 3) { // exaltation
// exaltation const exaltation = Misc.toInt(this.data.data.compteurs.exaltation.value) + moral - 3;
compteurs.moral.value--; await this.update({ 'data.compteurs.exaltation.value': exaltation });
compteurs.exaltation.value = Misc.toInt(compteurs.exaltation.value) + 1;
} }
if (compteurs.moral.value < -3) { if (moral < -3) { // dissolution
// dissolution const dissolution = Misc.toInt(this.data.data.compteurs.dissolution.value) + 3 - moral;
compteurs.moral.value++; await this.update({ 'data.compteurs.dissolution.value': dissolution });
compteurs.dissolution.value = Misc.toInt(compteurs.dissolution.value) + 1;
} }
await this.update({ 'data.compteurs': compteurs }); moral = Math.max(-3, Math.min(moral, 3));
await this.update({ 'data.compteurs.moral.value': moral });
} }
return compteurs.moral.value; return this.data.data.compteurs.moral.value;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -1576,11 +1497,14 @@ export class RdDActor extends Actor {
const ajustementEthylique = ethylisme.value; const ajustementEthylique = ethylisme.value;
// Qui a bu boira (p 164) // Qui a bu boira (p 164)
let rollVolonte = await RdDResolutionTable.roll(this.data.data.carac.volonte.value, Math.min(ajustementEthylique, 0) + this.data.data.compteurs.moral.value); let rollVolonte = await RdDResolutionTable.roll(this.data.data.carac.volonte.value, Math.min(ajustementEthylique, 0) + this.data.data.compteurs.moral.value);
msgText += `Vous avez échoué à votre jet d'éthylisme, vous êtes maintenant ${RdDUtility.getNomEthylisme(ajustementEthylique)} (${ajustementEthylique}).` const quiABuBoira = (rollVolonte.isSuccess
msgText += "<br>" + RdDResolutionTable.explain(rollVolonte) + "<br>";
msgText += "Qui a bu boira : " + (rollVolonte.isSuccess
? "vous êtes libre de continuer à boire ou pas." ? "vous êtes libre de continuer à boire ou pas."
: "vous avez une envie irrépréssible de reprendre un verre."); : "vous avez une envie irrépréssible de reprendre un verre.");
msgText += `Vous avez échoué à votre jet d'éthylisme, vous êtes
maintenant ${RdDUtility.getNomEthylisme(ajustementEthylique)} (${ajustementEthylique}).
<br> ${RdDResolutionTable.explain(rollVolonte)}
<br>Qui a bu boira : ${quiABuBoira}`;
} }
ChatMessage.create({ ChatMessage.create({
@ -1774,7 +1698,7 @@ export class RdDActor extends Actor {
if (!rollData.useMoral) return; if (!rollData.useMoral) return;
if (rollData.rolled.isEchec || if (rollData.rolled.isEchec ||
(rollData.ajustements.diviseurSignificative && (rollData.rolled.roll * rollData.ajustements.diviseurSignificative > rollData.score))) { (rollData.ajustements.diviseurSignificative && (rollData.rolled.roll * rollData.ajustements.diviseurSignificative > rollData.score))) {
rollData.perteMoralEchec = rollData.moral<=-3? 'dissolution' : 'perte'; rollData.perteMoralEchec = rollData.moral <= -3 ? 'dissolution' : 'perte';
rollData.moral = await this.moralIncDec(-1); /* L'appel au moral a échoué. Le personnage perd un point de moral */ rollData.moral = await this.moralIncDec(-1); /* L'appel au moral a échoué. Le personnage perd un point de moral */
} }
} }
@ -2863,42 +2787,29 @@ export class RdDActor extends Actor {
return; return;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async optimizeArgent(sumDenier) { async optimizeArgent(sumDenier, monnaies) {
let sols = Math.floor(sumDenier / 100);
let deniers = sumDenier - (sols * 100);
let nbOr = Math.floor(sols / 10);
let nbArgent = sols - (nbOr * 10);
let nbBronze = Math.floor(deniers / 10);
let nbEtain = deniers - (nbBronze * 10);
// console.log("ARGENT", nbOr, nbArgent, nbBronze, nbEtain); let parValeur = Misc.classifyFirst(monnaies, it => it.data.valeur_deniers);
let piece = this.data.items.find(item => item.type == 'monnaie' && item.data.valeur_deniers == 1000); let fortune = {
if (piece) { 1000: Math.floor(sumDenier / 1000), // or
let update = { _id: piece._id, 'data.quantite': nbOr }; 100: Math.floor(sumDenier / 100) % 10, // argent
const updated = await this.updateEmbeddedEntity("OwnedItem", update); 10: Math.floor(sumDenier / 10) % 10, // bronze
1: sumDenier % 10 // étain
} }
for (const [valeur, nombre] of Object.entries(fortune)) {
piece = this.data.items.find(item => item.type == 'monnaie' && item.data.valeur_deniers == 100); let piece = parValeur[valeur];
if (piece) { await this.updateEmbeddedEntity("OwnedItem", { _id: piece._id, 'data.quantite': nombre });
let update = { _id: piece._id, 'data.quantite': nbArgent };
const updated = await this.updateEmbeddedEntity("OwnedItem", update);
}
piece = this.data.items.find(item => item.type == 'monnaie' && item.data.valeur_deniers == 10);
if (piece) {
let update = { _id: piece._id, 'data.quantite': nbBronze };
const updated = await this.updateEmbeddedEntity("OwnedItem", update);
}
piece = this.data.items.find(item => item.type == 'monnaie' && item.data.valeur_deniers == 1);
if (piece) {
let update = { _id: piece._id, 'data.quantite': nbEtain };
const updated = await this.updateEmbeddedEntity("OwnedItem", update);
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async payerDenier(sumDenier, dataObj = undefined, quantite = 1) { async payerDenier(sumDenier, dataObj = undefined, quantite = 1) {
let monnaies = Monnaie.filtrerMonnaies(this.data.items);
if (monnaies.length < 4) {
ui.notifications.warn("Problème de monnaies manquantes, impossible de payer correctement!")
return;
}
sumDenier = Number(sumDenier); sumDenier = Number(sumDenier);
let denierDisponible = 0; let denierDisponible = 0;
@ -2912,19 +2823,18 @@ export class RdDActor extends Actor {
let isPayed = false; let isPayed = false;
if (denierDisponible >= sumDenier) { if (denierDisponible >= sumDenier) {
denierDisponible -= sumDenier; denierDisponible -= sumDenier;
this.optimizeArgent(denierDisponible); this.optimizeArgent(denierDisponible, monnaies);
msg = `Vous avez payé <strong>${sumDenier} Deniers</strong>, qui ont été soustraits de votre argent.`; msg = `Vous avez payé <strong>${sumDenier} Deniers</strong>, qui ont été soustraits de votre argent.`;
RdDAudio.PlayContextAudio("argent"); // Petit son RdDAudio.PlayContextAudio("argent"); // Petit son
isPayed = true; isPayed = true;
if (dataObj) {
dataObj.payload.data.cout = sumDenier / 100; // Mise à jour du prix en sols , avec le prix acheté
dataObj.payload.data.quantite = quantite;
await this.createOwnedItem(dataObj.payload);
msg += `<br>Et l'objet <strong>${dataObj.payload.name}</strong> a été ajouté à votre inventaire.`;
}
} else { } else {
msg = "Vous n'avez pas assez d'argent pour paye cette somme !"; msg = "Vous n'avez pas assez d'argent pour payer cette somme !";
}
if (dataObj && isPayed) {
dataObj.payload.data.cout = sumDenier / 100; // Mise à jour du prix en sols , avec le prix acheté
dataObj.payload.data.quantite = quantite;
await this.createOwnedItem(dataObj.payload);
msg += `<br>Et l'objet <strong>${dataObj.payload.name}</strong> a été ajouté à votre inventaire.`;
} }
let message = { let message = {
@ -2938,10 +2848,8 @@ export class RdDActor extends Actor {
async monnaieIncDec(id, value) { async monnaieIncDec(id, value) {
let monnaie = this.data.items.find(item => item.type == 'monnaie' && item._id == id); let monnaie = this.data.items.find(item => item.type == 'monnaie' && item._id == id);
if (monnaie) { if (monnaie) {
monnaie.data.quantite += value; const quantite = Math.max(0, monnaie.data.quantite + value);
if (monnaie.data.quantite < 0) monnaie.data.quantite = 0; // Sanity check await this.updateEmbeddedEntity("OwnedItem", { _id: monnaie._id, 'data.quantite': quantite });
const update = { _id: monnaie._id, 'data.quantite': monnaie.data.quantite };
const updated = await this.updateEmbeddedEntity("OwnedItem", update);
} }
} }

View File

@ -31,6 +31,13 @@ const categorieCompetences = {
"lancer": { level: "-8", label: "Lancer" } "lancer": { level: "-8", label: "Lancer" }
} }
const compendiumCompetences = {
"personnage": "foundryvtt-reve-de-dragon.competences",
"creature": "foundryvtt-reve-de-dragon.competences-creatures",
"entite": "foundryvtt-reve-de-dragon.competences-entites"
};
function _buildCumulXP() { function _buildCumulXP() {
let cumulXP = { "-11": 0 }; let cumulXP = { "-11": 0 };
let cumul = 0; let cumul = 0;
@ -46,6 +53,10 @@ const competence_xp_cumul = _buildCumulXP();
export class RdDItemCompetence extends Item { export class RdDItemCompetence extends Item {
static actorCompendium(actorType) {
return compendiumCompetences[actorType];
}
static getCategorieCompetences() { static getCategorieCompetences() {
return categorieCompetences; return categorieCompetences;
} }

40
module/item-monnaie.js Normal file
View File

@ -0,0 +1,40 @@
const monnaiesData = [
{
_id: randomID(16), name: "Etain (1 denier)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp",
data: { quantite: 0, valeur_deniers: 1, encombrement: 0.001, description: "" }
},
{
_id: randomID(16), name: "Bronze (10 deniers)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_bronze_epees.webp",
data: { quantite: 0, valeur_deniers: 10, encombrement: 0.002, description: "" }
},
{
_id: randomID(16), name: "Argent (1 sol)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_argent_sol.webp",
data: { quantite: 0, valeur_deniers: 100, encombrement: 0.003, description: "" }
},
{
_id: randomID(16), name: "Or (10 sols)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_or_sol.webp",
data: { quantite: 0, valeur_deniers: 1000, encombrement: 0.004, description: "" }
}
]
export class Monnaie {
static monnaiesData() {
return monnaiesData;
}
static filtrerMonnaies(items) {
return items.filter(it => it.type == 'monnaie');
}
static monnaiesManquantes(items) {
const valeurs = Monnaie.filtrerMonnaies(items)
.map(it => it.data.valeur_deniers)
return duplicate(monnaiesData.filter(monnaie => !valeurs.find(v => v != monnaie.data.valeur_deniers)));
}
}

View File

@ -47,6 +47,17 @@ export class Misc {
return itemsBy; return itemsBy;
} }
static classifyFirst(items, classifier) {
let itemsBy = {};
for (const item of items) {
const classification = classifier(item);
if (!itemsBy[classification]) {
itemsBy[classification] = item;
}
}
return itemsBy;
}
static classifyInto(itemsBy, items, classifier = it => it.type, transform = it => it) { static classifyInto(itemsBy, items, classifier = it => it.type, transform = it => it) {
for (const item of items) { for (const item of items) {
const classification = classifier(item); const classification = classifier(item);

44
module/poetique.txt Normal file
View File

@ -0,0 +1,44 @@
Le courant du Fleuve
Te domine et te Porte
Avant que tu te moeuves
Combat le, ou il t'emporte
A vous qui faites ripaille
sourds aux damnés de la faim
à vous qui livrez
une inégale bataille
à ceux qui vous tendent la main
Ils sont tout près ! - Tenons fermée
<br>Cette salle, où nous les narguons.
<br>Quel bruit dehors ! Hideuse armée
<br>De vampires et de dragons !
<br>La poutre du toit descellée
<br>Ploie ainsi qu'une herbe mouillée,
<br>Et la vieille porte rouillée
<br>Tremble, à déraciner ses gonds !`),
https://www.poetica.fr/poeme-1423/guy-de-maupassant-le-sommeil-du-mandarin/
Le monde est un rêve de Dragons. Nous
ne savons pas qui sont les Dragons ni à quoi
ils ressemblent, en dépit de lantique iconographie qui les dépeint comme de gigantesques créatures ailées capables de cracher
feu et flammes.
Car parmi les humains, autre nom lui est donné,
Nom sinistre parmi tous, nom funèbre, c'est la mort!
Un ami disparu... Thanatos est passé...
Messieurs, ne crachez pas de jurons ni d'ordure
Au visage fardé de cette pauvre impure
Que déesse Famine a par un soir d'hiver,
Contrainte à relever ses jupons en plein air.

View File

@ -147,6 +147,7 @@ export class RdDCalendrier extends Application {
} }
} }
} }
this.listeNombreAstral = newList;
game.settings.set("foundryvtt-reve-de-dragon", "liste-nombre-astral", this.listeNombreAstral); game.settings.set("foundryvtt-reve-de-dragon", "liste-nombre-astral", this.listeNombreAstral);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -1,5 +1,4 @@
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { RdDUtility } from "./rdd-utility.js";
const tableCaracDerivee = { const tableCaracDerivee = {
// xp: coût pour passer du niveau inférieur à ce niveau // xp: coût pour passer du niveau inférieur à ce niveau

View File

@ -72,11 +72,11 @@ export class RdDTMRDialog extends Dialog {
} }
loadSortsReserve() { loadSortsReserve() {
this.sortsReserves = duplicate(this.actor.data.data.reve.reserve.list); this.sortsReserves = this.actor.data.data.reve.reserve.list;
} }
loadRencontres() { loadRencontres() {
this.rencontresExistantes = duplicate(this.actor.getTMRRencontres()).list; this.rencontresExistantes = this.actor.getTMRRencontres();
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -389,6 +389,11 @@ export class RdDTMRDialog extends Dialog {
ChatMessage.create({ content: message, user: game.user._id, whisper: ChatMessage.getWhisperRecipients("GM") }); ChatMessage.create({ content: message, user: game.user._id, whisper: ChatMessage.getWhisperRecipients("GM") });
} }
/* -------------------------------------------- */
_tellToUserAndGM(message) {
ChatMessage.create({ content: message, user: game.user._id, whisper: [game.user._id].concat(ChatMessage.getWhisperRecipients("GM")) });
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async manageRencontre(tmr, postRencontre) { async manageRencontre(tmr, postRencontre) {
if (this.viewOnly) { if (this.viewOnly) {
@ -669,8 +674,8 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
async declencheSortEnReserve(coord) { async declencheSortEnReserve(coord) {
let sortReserveList = TMRUtility.getSortReserveList(this.sortsReserves, coord); let sortsEnCoord = TMRUtility.getSortsReserve(this.sortsReserves, coord);
if (sortReserveList.length > 0) { if (sortsEnCoord.length > 0) {
if (EffetsDraconiques.isSortReserveImpossible(this.actor)) { if (EffetsDraconiques.isSortReserveImpossible(this.actor)) {
ui.notifications.error("Une queue ou un souffle vous empèche de déclencher de sort!"); ui.notifications.error("Une queue ou un souffle vous empèche de déclencher de sort!");
return; return;
@ -678,7 +683,7 @@ export class RdDTMRDialog extends Dialog {
if (!EffetsDraconiques.isUrgenceDraconique(this.actor) && if (!EffetsDraconiques.isUrgenceDraconique(this.actor) &&
(EffetsDraconiques.isReserveEnSecurite(this.actor) || this.isReserveExtensible(coord))) { (EffetsDraconiques.isReserveEnSecurite(this.actor) || this.isReserveExtensible(coord))) {
let msg = "Vous êtes sur une case avec un Sort en Réserve. Grâce à votre Tête <strong>Reserve en Sécurité</strong> ou <strong>Réserve Exensible</strong>, vous pouvez contrôler le déclenchement. Cliquez si vous souhaitez le déclencher : <ul>"; let msg = "Vous êtes sur une case avec un Sort en Réserve. Grâce à votre Tête <strong>Reserve en Sécurité</strong> ou <strong>Réserve Exensible</strong>, vous pouvez contrôler le déclenchement. Cliquez si vous souhaitez le déclencher : <ul>";
for (let sortReserve of sortReserveList) { for (let sortReserve of sortsEnCoord) {
msg += "<li><a class='chat-card-button' id='sort-reserve' data-actor-id='" + this.actor._id + "' data-tmr-coord='" + coord + "' data-sort-id='" + sortReserve.sort._id + "'>" + sortReserve.sort.name + "</a></li>"; msg += "<li><a class='chat-card-button' id='sort-reserve' data-actor-id='" + this.actor._id + "' data-tmr-coord='" + coord + "' data-sort-id='" + sortReserve.sort._id + "'>" + sortReserve.sort.name + "</a></li>";
} }
msg += "</ol>"; msg += "</ol>";
@ -688,15 +693,14 @@ export class RdDTMRDialog extends Dialog {
}); });
return; return;
} }
await this.processSortReserve(sortReserveList[0]); await this.processSortReserve(sortsEnCoord[0]);
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
lancerSortEnReserve(coord, sortId) { lancerSortEnReserve(coord, sortId) {
let sortReserveList = TMRUtility.getSortReserveList(this.sortsReserves, coord); let sortEnCoord = TMRUtility.getSortsReserve(this.sortsReserves, coord);
let sortReserve = sortReserveList.find(sortReserve => sortReserve.sort._id == sortId); let sortReserve = sortEnCoord.find(sortReserve => sortReserve.sort._id == sortId);
//console.log("SORT RESA", sortReserveList, coordTMR, sortId, sortReserve);
if (sortReserve) { if (sortReserve) {
this.processSortReserve(sortReserve); this.processSortReserve(sortReserve);
} else { } else {
@ -712,7 +716,7 @@ export class RdDTMRDialog extends Dialog {
await this.actor.deleteSortReserve(sortReserve); await this.actor.deleteSortReserve(sortReserve);
//this.updateSortReserve(); //this.updateSortReserve();
console.log("declencheSortEnReserve", sortReserve) console.log("declencheSortEnReserve", sortReserve)
this._tellToGM(`Vous avez déclenché le sort en réserve <strong> ${sortReserve.sort.name}</strong> this._tellToUserAndGM(`Vous avez déclenché le sort en réserve <strong> ${sortReserve.sort.name}</strong>
avec ${sortReserve.sort.data.ptreve_reel} points de Rêve avec ${sortReserve.sort.data.ptreve_reel} points de Rêve
en ${sortReserve.coord} (${TMRUtility.getTMRLabel(sortReserve.coord)}) en ${sortReserve.coord} (${TMRUtility.getTMRLabel(sortReserve.coord)})
`); `);

View File

@ -485,8 +485,10 @@ export class RdDUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async loadCompendium(compendium, filter = item => true) { static async loadCompendium(compendium, filter = item => true) {
if (!compendium){
return [];
}
let compendiumItems = await RdDUtility.loadCompendiumNames(compendium); let compendiumItems = await RdDUtility.loadCompendiumNames(compendium);
const pack = game.packs.get(compendium); const pack = game.packs.get(compendium);
let list = []; let list = [];
for (let compendiumItem of compendiumItems) { for (let compendiumItem of compendiumItems) {

View File

@ -432,7 +432,7 @@ export class TMRUtility {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getSortReserveList(reserveList, coord) { static getSortsReserve(reserveList, coord) {
// TODO : Gérer les têtes spéciales réserve! // TODO : Gérer les têtes spéciales réserve!
let tmrDescr = this.getTMR(coord); let tmrDescr = this.getTMR(coord);
//console.log("Sort réserve : ", tmrDescr); //console.log("Sort réserve : ", tmrDescr);

View File

@ -2,7 +2,7 @@
"name": "foundryvtt-reve-de-dragon", "name": "foundryvtt-reve-de-dragon",
"title": "Rêve de Dragon", "title": "Rêve de Dragon",
"description": "Rêve de Dragon RPG for FoundryVTT", "description": "Rêve de Dragon RPG for FoundryVTT",
"version": "1.3.35", "version": "1.3.36",
"manifestPlusVersion": "1.0.0", "manifestPlusVersion": "1.0.0",
"minimumCoreVersion": "0.7.5", "minimumCoreVersion": "0.7.5",
"compatibleCoreVersion": "0.7.9", "compatibleCoreVersion": "0.7.9",

View File

@ -541,7 +541,6 @@
</div> </div>
{{!-- hautreve Tab --}} {{!-- hautreve Tab --}}
{{log 'Haut reve' hautreve}}
<div class="tab hautreve " data-group="primary" data-tab="hautreve" style="height:200px"> <div class="tab hautreve " data-group="primary" data-tab="hautreve" style="height:200px">
<div> <div>
<h3>Haut rêve:</h3> <h3>Haut rêve:</h3>

1
templates/logger.html Normal file
View File

@ -0,0 +1 @@
{{log 'HandleBars' this}}