diff --git a/module/actor.js b/module/actor.js index ee1e39af..68bf750e 100644 --- a/module/actor.js +++ b/module/actor.js @@ -26,6 +26,7 @@ import { Poetique } from "./poetique.js"; import { EffetsDraconiques } from "./tmr/effets-draconiques.js"; import { Draconique } from "./tmr/draconique.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) { - // Case of compendium global import if (data instanceof Array) { 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 (data.items) { let actor = super.create(data, options); - if (data.type == "personnage") { + if (isPersonnage) { await actor.checkMonnaiePresence(data.items); } return actor; } - let compendiumName; - if (data.type == "personnage") { - compendiumName = "foundryvtt-reve-de-dragon.competences"; - } else if (data.type == "creature") { - compendiumName = "foundryvtt-reve-de-dragon.competences-creatures"; - } else if (data.type == "entite") { - compendiumName = "foundryvtt-reve-de-dragon.competences-entites"; + data.items = await RdDUtility.loadCompendium(RdDItemCompetence.actorCompendium(data.type)); + if (isPersonnage) { + data.items = data.items.concat(Monnaie.monnaiesData()); } - 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); } @@ -151,41 +141,10 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async checkMonnaiePresence(items) { // Ajout opportuniste si les pièces n'existent pas. if (!items) return; // Sanity check during import - let piece = items.find(item => item.type == 'monnaie' && Number(item.data.valeur_deniers) == 1); - let newMonnaie = []; - if (!piece) { - newMonnaie.push(RdDUtility.createMonnaie("Etain (1 denier)", 1, "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp")); + let manquantes = Monnaie.monnaiesManquantes(items); + if (manquantes.length > 0) { + await this.createOwnedItem(manquantes); } - 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() { const list = this.getDraconicList().sort((a, b) => b.data.niveau - a.data.niveau); if (list.length == 0) { - return { name: "none", data: { niveau: -11 } }; + return { name: "Aucun", data: { niveau: -11 } }; } return duplicate(list[0]); } @@ -350,27 +309,30 @@ export class RdDActor extends Actor { }; 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, "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.update({ "data.blessures": blessures }); await this._recupererVie(message); await this.jetDeMoral('neutre'); - - // On ne récupère un point de chance que si aucun appel à la chance dans la journée - 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._recupereChance(); + await this.transformerStress(); await this.retourSeuilDeReve(message); message.content = `A la fin Chateau Dormant, ${message.content}
Un nouveau jour se lève`; 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) { 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("endurance", this.data.data.sante.endurance.max - this.data.data.sante.endurance.value); if (this.data.data.sante.fatigue) { - let fatigue = duplicate(this.data.data.sante.fatigue) - fatigue.value = 0; - await this.update({ "data.sante.fatigue": fatigue }); + await this.update({ "data.sante.fatigue.value": 0 }); } } ChatMessage.create(message); @@ -532,16 +492,16 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async recupererFatigue(message) { - let fatigue = duplicate(this.data.data.sante.fatigue) + let fatigue = this.data.data.sante.fatigue.value; const fatigueMin = this._computeFatigueMin(); - if (fatigue.value <= fatigueMin) { + if (fatigue <= fatigueMin) { message.content += "Vous êtes déjà reposé. "; return; } - fatigue.value = Math.max(fatigueMin, this._calculRecuperationSegment(fatigue.value)); + fatigue = Math.max(fatigueMin, this._calculRecuperationSegment(fatigue)); console.log("recupererFatigue", fatigue) - await this.update({ "data.sante.fatigue": fatigue }); - if (fatigue.value == 0) { + await this.update({ "data.sante.fatigue.value": fatigue }); + if (fatigue == 0) { message.content += "Vous êtes complêtement reposé. "; } } @@ -680,9 +640,9 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async sortMisEnReserve(rollData, sort) { - let reserve = duplicate(this.data.data.reve.reserve); - reserve.list.push({ coord: rollData.tmr.coord, sort: sort, draconic: duplicate(rollData.competence) }); - await this.update({ "data.reve.reserve": reserve }); + let reserve = duplicate(this.data.data.reve.reserve.list); + reserve.push({ coord: rollData.tmr.coord, sort: sort, draconic: duplicate(rollData.competence) }); + await this.update({ "data.reve.reserve.list": reserve }); this.currentTMR.updateTokens(); } @@ -752,7 +712,7 @@ export class RdDActor extends Actor { }); } 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 { console.log("Competence not found", compName); } @@ -765,7 +725,7 @@ export class RdDActor extends Actor { compValue = compValue ?? 0; this.checkCompetenceXP(compName, 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 { console.log("Competence not found", compName); } @@ -778,7 +738,7 @@ export class RdDActor extends Actor { if (comp) { compValue = compValue ?? 0; 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 { console.log("Competence not found", compName); } @@ -790,7 +750,7 @@ export class RdDActor extends Actor { if (comp) { compValue = compValue ?? 0; 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 { console.log("Competence not found", compName); } @@ -798,7 +758,6 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async updateCompteurValue(fieldName, fieldValue) { - //console.log("Update", fieldName, fieldValue); let compteurs = duplicate(this.data.data.compteurs); compteurs[fieldName].value = fieldValue; await this.update({ "data.compteurs": compteurs }); @@ -992,8 +951,6 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async computeEncombrementTotalEtMalusArmure() { let encTotal = 0; - - let malusArmureData = (this.data.data.attributs && this.data.data.attributs.malusarmure) ? duplicate(this.data.data.attributs.malusarmure) : {}; let newMalusArmure = 0; for (const item of this.data.items) { 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 this.encTotal = encTotal; this.detectSurEncombrement(); + // Mise à jour éventuelle du malus armure - if (this.data.data.attributs && this.data.data.attributs.malusarmure && newMalusArmure != malusArmureData.value) { - malusArmureData.value = newMalusArmure; - await this.update({ "data.attributs.malusarmure": malusArmureData }); + if (this.data.data.attributs?.malusarmure && newMalusArmure != this.data.data.attributs.malusarmure.value) { + await this.update({ "data.attributs.malusarmure.value ": newMalusArmure }); } return this.encTotal; } @@ -1049,12 +1006,12 @@ export class RdDActor extends Actor { let resume = "Blessures:"; if (nbCritiques > 0 || nbGraves > 0 || nbLegeres > 0) { if (nbLegeres > 0) { - resume += " " + nbLegeres + " légères"; + resume += " " + nbLegeres + " légère" + (nbLegeres > 1 ? "s" : ""); } if (nbGraves > 0) { if (nbLegeres > 0) resume += ","; - resume += " " + nbGraves + " graves"; + resume += " " + nbGraves + " grave" + (nbGraves > 1 ? "s" : ""); } if (nbCritiques > 0) { if (nbGraves > 0 || nbLegeres > 0) @@ -1063,7 +1020,7 @@ export class RdDActor extends Actor { } } else { - resume += " aucune"; + resume = "Aucune blessure"; } return resume; } @@ -1093,20 +1050,14 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async ajouterRefoulement(value = 1) { - let ret = "none"; - - let refoulement = duplicate(this.data.data.reve.refoulement); - refoulement.value = refoulement.value + value; - + let refoulement = this.data.data.reve.refoulement.value + value; let total = new Roll("1d20").roll().total; - if (total <= refoulement.value) { - refoulement.value = 0; - this.ajouterSouffle({ chat: true }); - ret = "souffle"; + if (total <= refoulement) { + refoulement = 0; + await this.ajouterSouffle({ chat: true }); } - - await this.update({ "data.reve.refoulement": refoulement }); - return ret; + await this.update({ "data.reve.refoulement.value": refoulement }); + return refoulement == 0 ? "souffle" : "none"; } /* -------------------------------------------- */ @@ -1119,7 +1070,6 @@ export class RdDActor extends Actor { content: this.name + " subit un Souffle de Dragon : " + souffle.name }); } - // TODO: fermeture cité return souffle; } @@ -1128,9 +1078,7 @@ export class RdDActor extends Actor { let queue; if (this.data.data.reve.reve.thanatosused) { queue = await RdDRollTables.getOmbre(); - let myReve = duplicate(this.data.data.reve.reve); - myReve.thanatosused = false; - await this.update({ "data.reve.reve": myReve }); + await this.update({ "data.reve.reve.thanatosused": false }); } else { queue = await RdDRollTables.getQueue(); @@ -1165,40 +1113,25 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ getTMRRencontres() { - return this.data.data.reve.rencontre; + return this.data.data.reve.rencontre.list; } /* -------------------------------------------- */ async deleteTMRRencontreAtPosition() { - let rencontres = duplicate(this.getTMRRencontres()); - let len = rencontres.list.length; - let i = 0; - //console.log("List", rencontres, len); - 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 }); + let rencontres = this.getTMRRencontres(); + let newRencontres = rencontres.filter(it => it.coord != this.getDemiReve()); + if (newRencontres.length != rencontres.length) { + await this.update({ "data.reve.rencontre.list": newRencontres }); } } /* -------------------------------------------- */ async addTMRRencontre(currentRencontre) { - let rencontres = duplicate(this.getTMRRencontres()); - let len = rencontres.list.length; - let i = 0; - let already = false; - for (i = 0; i < len; i++) { - if (rencontres.list[i].coord == this.getDemiReve()) - already = true; - } - if (!already) { - rencontres.list.push(currentRencontre); - await this.update({ "data.reve.rencontre": rencontres }); + let rencontres = this.getTMRRencontres(); + let newRencontres = rencontres.filter(it => it.coord != this.getDemiReve()); + if (newRencontres.length == rencontres.length) { + newRencontres.push(currentRencontre); + await this.update({ "data.reve.rencontre": newRencontres }); } } @@ -1220,9 +1153,8 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async reveActuelIncDec(value) { - let reve = duplicate(this.data.data.reve.reve); - reve.value = Math.max(reve.value + value, 0); - await this.update({ "data.reve.reve": reve }); + let reve = Math.max(this.data.data.reve.reve.value + value, 0); + await this.update({ "data.reve.reve.value": reve }); } /* -------------------------------------------- */ @@ -1235,17 +1167,13 @@ export class RdDActor extends Actor { } /* -------------------------------------------- */ - async setPointsDeSeuil(value) { - let seuil = duplicate(this.data.data.reve.seuil); - seuil.value = value; - await this.update({ "data.reve.seuil": seuil }); + async setPointsDeSeuil(seuil) { + await this.update({ "data.reve.seuil.value": seuil }); } /* -------------------------------------------- */ - async setPointsDeChance(value) { - let chance = duplicate(this.data.data.compteurs.chance); - chance.value = value; - await this.update({ "data.compteurs.chance": chance }); + async setPointsDeChance(chance) { + await this.update({ "data.compteurs.chance.value": chance }); } /* -------------------------------------------- */ @@ -1299,7 +1227,7 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async testSiSonne(sante, endurance) { - const roll = new Roll("1d20").roll(); + const roll = new Roll("1d20").evaluate(); roll.showDice = true; RdDDice.show(roll); let result = { @@ -1307,18 +1235,20 @@ export class RdDActor extends Actor { sonne: roll.total > endurance || roll.total == 20 // 20 is always a failure } if (roll.total == 1) { - let xp = Misc.toInt(this.data.data.carac.constitution.xp) + 1; - this.update({ "data.carac.constitution.xp": xp }); // +1 XP ! + await this.ajoutXpConstitution(1); // +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).` }); } if (result.sonne) { - await this.setSonne(); sante.sonne.value = true; } return result; } + async ajoutXpConstitution(xp) { + await this.update({ "data.carac.constitution.xp": Misc.toInt(this.data.data.carac.constitution.xp) + xp }); + } + /* -------------------------------------------- */ countBlessures(blessuresListe) { 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)) { msgText += `${this.name} a réussi son Jet d'Endurance !`; if (myRoll.total == 1) { + await this.ajoutXpConstitution(); 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 { - msgText += `${this.name} a échoué son Jet d'Endurance et devient Sonné`; await this.setSonne(); + msgText += `${this.name} a échoué son Jet d'Endurance et devient Sonné`; } const message = { content: msgText, @@ -1454,29 +1382,25 @@ export class RdDActor extends Actor { } /* -------------------------------------------- */ - async manageBlessureFromSheet(bType, index, active) { - let bList = duplicate(this.data.data.blessures); - let blessure = bList[bType + "s"].liste[index]; + async manageBlessureFromSheet(gravite, index) { + let listBlessures = duplicate(this.data.data.blessures); + let blessure = listBlessures[gravite + "s"].liste[index]; blessure.active = !blessure.active; if (!blessure.active) { - blessure.premiers_soins = 0; - blessure.soins_complets = 0; - blessure.jours = 0; - blessure.loc = ""; + this._supprimerBlessure(blessure); } - //console.log("Blessure update", bType, index, blessure, bList ); - await this.update({ 'data.blessures': bList }); + await this.update({ 'data.blessures': listBlessures }); } /* -------------------------------------------- */ - async setDataBlessureFromSheet(bType, index, psoins, pcomplets, jours, loc) { - let bList = duplicate(this.data.data.blessures); - let blessure = bList[bType + "s"].liste[index]; + async setDataBlessureFromSheet(gravite, index, psoins, pcomplets, jours, loc) { + let listBlessures = duplicate(this.data.data.blessures); + let blessure = listBlessures[gravite + "s"].liste[index]; blessure.premiers_soins = psoins; blessure.soins_complets = pcomplets; blessure.jours = jours; 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) { - let compteurs = duplicate(this.data.data.compteurs); - compteurs.moral.value = Misc.toInt(compteurs.moral.value);; if (ajustementMoral != 0) { - compteurs.moral.value += ajustementMoral; - if (compteurs.moral.value > 3) { - // exaltation - compteurs.moral.value--; - compteurs.exaltation.value = Misc.toInt(compteurs.exaltation.value) + 1; + let moral = Misc.toInt(this.data.data.compteurs.moral.value) + ajustementMoral + if (moral > 3) { // exaltation + const exaltation = Misc.toInt(this.data.data.compteurs.exaltation.value) + moral - 3; + await this.update({ 'data.compteurs.exaltation.value': exaltation }); } - if (compteurs.moral.value < -3) { - // dissolution - compteurs.moral.value++; - compteurs.dissolution.value = Misc.toInt(compteurs.dissolution.value) + 1; + if (moral < -3) { // dissolution + const dissolution = Misc.toInt(this.data.data.compteurs.dissolution.value) + 3 - moral; + await this.update({ 'data.compteurs.dissolution.value': dissolution }); } - 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; // 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); - msgText += `Vous avez échoué à votre jet d'éthylisme, vous êtes maintenant ${RdDUtility.getNomEthylisme(ajustementEthylique)} (${ajustementEthylique}).` - msgText += "
" + RdDResolutionTable.explain(rollVolonte) + "
"; - msgText += "Qui a bu boira : " + (rollVolonte.isSuccess + const quiABuBoira = (rollVolonte.isSuccess ? "vous êtes libre de continuer à boire ou pas." : "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}). +
${RdDResolutionTable.explain(rollVolonte)} +
Qui a bu boira : ${quiABuBoira}`; } ChatMessage.create({ @@ -1774,7 +1698,7 @@ export class RdDActor extends Actor { if (!rollData.useMoral) return; if (rollData.rolled.isEchec || (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 */ } } @@ -2863,42 +2787,29 @@ export class RdDActor extends Actor { return; } /* -------------------------------------------- */ - async optimizeArgent(sumDenier) { - 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); + async optimizeArgent(sumDenier, monnaies) { - // console.log("ARGENT", nbOr, nbArgent, nbBronze, nbEtain); - let piece = this.data.items.find(item => item.type == 'monnaie' && item.data.valeur_deniers == 1000); - if (piece) { - let update = { _id: piece._id, 'data.quantite': nbOr }; - const updated = await this.updateEmbeddedEntity("OwnedItem", update); + let parValeur = Misc.classifyFirst(monnaies, it => it.data.valeur_deniers); + let fortune = { + 1000: Math.floor(sumDenier / 1000), // or + 100: Math.floor(sumDenier / 100) % 10, // argent + 10: Math.floor(sumDenier / 10) % 10, // bronze + 1: sumDenier % 10 // étain } - - piece = this.data.items.find(item => item.type == 'monnaie' && item.data.valeur_deniers == 100); - if (piece) { - 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); + for (const [valeur, nombre] of Object.entries(fortune)) { + let piece = parValeur[valeur]; + await this.updateEmbeddedEntity("OwnedItem", { _id: piece._id, 'data.quantite': nombre }); } } /* -------------------------------------------- */ 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); let denierDisponible = 0; @@ -2912,19 +2823,18 @@ export class RdDActor extends Actor { let isPayed = false; if (denierDisponible >= sumDenier) { denierDisponible -= sumDenier; - this.optimizeArgent(denierDisponible); + this.optimizeArgent(denierDisponible, monnaies); msg = `Vous avez payé ${sumDenier} Deniers, qui ont été soustraits de votre argent.`; RdDAudio.PlayContextAudio("argent"); // Petit son 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 += `
Et l'objet ${dataObj.payload.name} a été ajouté à votre inventaire.`; + } } else { - msg = "Vous n'avez pas assez d'argent pour paye 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 += `
Et l'objet ${dataObj.payload.name} a été ajouté à votre inventaire.`; + msg = "Vous n'avez pas assez d'argent pour payer cette somme !"; } let message = { @@ -2938,10 +2848,8 @@ export class RdDActor extends Actor { async monnaieIncDec(id, value) { let monnaie = this.data.items.find(item => item.type == 'monnaie' && item._id == id); if (monnaie) { - monnaie.data.quantite += value; - if (monnaie.data.quantite < 0) monnaie.data.quantite = 0; // Sanity check - const update = { _id: monnaie._id, 'data.quantite': monnaie.data.quantite }; - const updated = await this.updateEmbeddedEntity("OwnedItem", update); + const quantite = Math.max(0, monnaie.data.quantite + value); + await this.updateEmbeddedEntity("OwnedItem", { _id: monnaie._id, 'data.quantite': quantite }); } } diff --git a/module/item-competence.js b/module/item-competence.js index c7be84c7..98a422f6 100644 --- a/module/item-competence.js +++ b/module/item-competence.js @@ -31,6 +31,13 @@ const categorieCompetences = { "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() { let cumulXP = { "-11": 0 }; let cumul = 0; @@ -46,6 +53,10 @@ const competence_xp_cumul = _buildCumulXP(); export class RdDItemCompetence extends Item { + static actorCompendium(actorType) { + return compendiumCompetences[actorType]; + } + static getCategorieCompetences() { return categorieCompetences; } diff --git a/module/item-monnaie.js b/module/item-monnaie.js new file mode 100644 index 00000000..b0a76110 --- /dev/null +++ b/module/item-monnaie.js @@ -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))); + } +} diff --git a/module/misc.js b/module/misc.js index f1220c35..8f972c7b 100644 --- a/module/misc.js +++ b/module/misc.js @@ -47,6 +47,17 @@ export class Misc { 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) { for (const item of items) { const classification = classifier(item); diff --git a/module/poetique.txt b/module/poetique.txt new file mode 100644 index 00000000..35c1a630 --- /dev/null +++ b/module/poetique.txt @@ -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 +
Cette salle, où nous les narguons. +
Quel bruit dehors ! Hideuse armée +
De vampires et de dragons ! +
La poutre du toit descellée +
Ploie ainsi qu'une herbe mouillée, +
Et la vieille porte rouillée +
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 l’antique 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. + diff --git a/module/rdd-calendrier.js b/module/rdd-calendrier.js index be658177..15f69467 100644 --- a/module/rdd-calendrier.js +++ b/module/rdd-calendrier.js @@ -147,6 +147,7 @@ export class RdDCalendrier extends Application { } } } + this.listeNombreAstral = newList; game.settings.set("foundryvtt-reve-de-dragon", "liste-nombre-astral", this.listeNombreAstral); } /* -------------------------------------------- */ diff --git a/module/rdd-carac.js b/module/rdd-carac.js index 516b4f9f..6dbe169c 100644 --- a/module/rdd-carac.js +++ b/module/rdd-carac.js @@ -1,5 +1,4 @@ import { Grammar } from "./grammar.js"; -import { RdDUtility } from "./rdd-utility.js"; const tableCaracDerivee = { // xp: coût pour passer du niveau inférieur à ce niveau diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js index cbc1aafe..b1fe330a 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -72,11 +72,11 @@ export class RdDTMRDialog extends Dialog { } loadSortsReserve() { - this.sortsReserves = duplicate(this.actor.data.data.reve.reserve.list); + this.sortsReserves = this.actor.data.data.reve.reserve.list; } 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") }); } + /* -------------------------------------------- */ + _tellToUserAndGM(message) { + ChatMessage.create({ content: message, user: game.user._id, whisper: [game.user._id].concat(ChatMessage.getWhisperRecipients("GM")) }); + } + /* -------------------------------------------- */ async manageRencontre(tmr, postRencontre) { if (this.viewOnly) { @@ -669,8 +674,8 @@ export class RdDTMRDialog extends Dialog { /* -------------------------------------------- */ async declencheSortEnReserve(coord) { - let sortReserveList = TMRUtility.getSortReserveList(this.sortsReserves, coord); - if (sortReserveList.length > 0) { + let sortsEnCoord = TMRUtility.getSortsReserve(this.sortsReserves, coord); + if (sortsEnCoord.length > 0) { if (EffetsDraconiques.isSortReserveImpossible(this.actor)) { ui.notifications.error("Une queue ou un souffle vous empèche de déclencher de sort!"); return; @@ -678,7 +683,7 @@ export class RdDTMRDialog extends Dialog { if (!EffetsDraconiques.isUrgenceDraconique(this.actor) && (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 Reserve en Sécurité ou Réserve Exensible, vous pouvez contrôler le déclenchement. Cliquez si vous souhaitez le déclencher :