diff --git a/changelog.md b/changelog.md index 178fa015..d69694bd 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,13 @@ --- # v10.7 - L'os de Semolosse +## v10.7.14 - l'expérience de Semolosse +- Affichage des personnages accordés sur les fiches des entités +- Refonte du journal d'expérience + - disponible pour les personnages des joueurs + - explication "comptable" des changements (dépense ou ajout, changements de niveaux, ...) +- tri alphabétique des différentes listes (sorts, recettes, oeuvres, ...) + ## v10.7.13 - l'armure de Semolosse - Fix: en cas d'armure variable, la détérioration diminue le dé d'armure diff --git a/module/actor-entite-sheet.js b/module/actor-entite-sheet.js index d7a96ce0..50f505bf 100644 --- a/module/actor-entite-sheet.js +++ b/module/actor-entite-sheet.js @@ -1,4 +1,6 @@ import { RdDActorSheet } from "./actor-sheet.js"; +import { RdDSheetUtility } from "./rdd-sheet-utility.js"; +import { RdDUtility } from "./rdd-utility.js"; export class RdDActorEntiteSheet extends RdDActorSheet { @@ -13,6 +15,12 @@ export class RdDActorEntiteSheet extends RdDActorSheet { dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }] }); } + async getData() { + let formData = await super.getData(); + formData.resonances = this.actor.system.sante.resonnance.actors.map(actorId => game.actors.get(actorId)) + .map(actor => { return { id: actor.id, name: actor.name, img: actor.img } }) + return formData + } /* -------------------------------------------- */ /** @override */ @@ -35,6 +43,23 @@ export class RdDActorEntiteSheet extends RdDActorSheet { let compName = event.currentTarget.attributes.compname.value; this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value)); }); + this.html.find('.resonance-delete').click(async event => { + const li = RdDSheetUtility.getEventElement(event); + const actorId = li.data("actor-id"); + if (actorId) { + const actorResonance = game.actors.get(actorId); + RdDUtility.confirmerSuppressionSubacteur(this, actorResonance, li, () => { + console.log('Delete : ', actorId); + this.removeSubacteur(actorId); + RdDUtility.slideOnDelete(this, li); + }); + } + }); + } + + async removeSubacteur(actorId) { + let newResonances = this.actor.system.sante.resonnance.actors.filter(id => id != actorId); + await this.actor.update({ 'system.sante.resonnance.actors': newResonances }, { renderSheet: false }); } } diff --git a/module/actor-sheet.js b/module/actor-sheet.js index d19ef734..9ff645e3 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -129,7 +129,11 @@ export class RdDActorSheet extends RdDBaseActorSheet { const actorId = li.data("actor-id"); if (actorId) { const subActor = game.actors.get(actorId); - RdDUtility.confirmerSuppressionSubacteur(this, subActor, li); + RdDUtility.confirmerSuppressionSubacteur(this, subActor, li, () => { + console.log('Delete : ', subActor.id); + this.actor.removeSubacteur(subActor.id); + RdDUtility.slideOnDelete(this, li); + }); } }); this.html.find('.experiencelog-delete').click(async event => { @@ -142,6 +146,13 @@ export class RdDActorSheet extends RdDBaseActorSheet { const key = Number(li.data("key") ?? -1); await this.actor.deleteExperienceLog(0, key + 1); }); + this.html.find("input.derivee-value[name='system.compteurs.stress.value']").change(async event => { + this.actor.updateCompteurValue("stress", parseInt(event.target.value)); + }); + this.html.find("input.derivee-value[name='system.compteurs.experience.value']").change(async event => { + this.actor.updateCompteurValue("experience", parseInt(event.target.value)); + }); + this.html.find('.encaisser-direct').click(async event => { this.actor.encaisser(); }) diff --git a/module/actor.js b/module/actor.js index ed20d6ab..64adae39 100644 --- a/module/actor.js +++ b/module/actor.js @@ -37,6 +37,7 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDItemBlessure } from "./item/blessure.js"; import { AppAstrologie } from "./sommeil/app-astrologie.js"; import { RdDEmpoignade } from "./rdd-empoignade.js"; +import { ExperienceLog, XP_TOPIC } from "./actor/experience-log.js"; const POSSESSION_SANS_DRACONIC = { img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp', @@ -821,31 +822,40 @@ export class RdDActor extends RdDBaseActor { } /* -------------------------------------------- */ - async updateCarac(caracName, caracValue) { + async updateCarac(caracName, to) { if (caracName == "force") { - if (Number(caracValue) > this.getTaille() + 4) { + if (Number(to) > this.getTaille() + 4) { ui.notifications.warn("Votre FORCE doit être au maximum de TAILLE+4"); return; } } if (caracName == "reve") { - if (caracValue > Misc.toInt(this.system.reve.seuil.value)) { - this.setPointsDeSeuil(caracValue); + if (to > Misc.toInt(this.system.reve.seuil.value)) { + this.setPointsDeSeuil(to); } } if (caracName == "chance") { - if (caracValue > Misc.toInt(this.system.compteurs.chance.value)) { - this.setPointsDeChance(caracValue); + if (to > Misc.toInt(this.system.compteurs.chance.value)) { + this.setPointsDeChance(to); } } - await this.update({ [`system.carac.${caracName}.value`]: caracValue }); + let selectedCarac = RdDActor._findCaracByName(this.system.carac, caracName); + const from = selectedCarac.value + await this.update({ [`system.carac.${caracName}.value`]: to }); + await ExperienceLog.add(this, XP_TOPIC.CARAC, from, to, caracName); } /* -------------------------------------------- */ - async updateCaracXP(caracName, caracXP) { + async updateCaracXP(caracName, to) { if (caracName == 'Taille') { return; } + let selectedCarac = RdDActor._findCaracByName(this.system.carac, caracName); + if (!selectedCarac.derivee) { + const from = Number(selectedCarac.xp); + await this.update({ [`system.carac.${caracName}.xp`]: to }); + await ExperienceLog.add(this, XP_TOPIC.XPCARAC, from, to, caracName); + } this.checkCaracXP(caracName); } @@ -857,16 +867,19 @@ export class RdDActor extends RdDBaseActor { let carac = RdDActor._findCaracByName(this.system.carac, caracName); if (carac) { carac = duplicate(carac); - let xp = Number(carac.xp); - let value = Number(carac.value); - while (xp >= RdDCarac.getCaracNextXp(value) && xp > 0) { - xp -= RdDCarac.getCaracNextXp(value); - value++; + const fromXp = Number(carac.xp); + const fromValue = Number(carac.value); + let toXp = fromXp; + let toValue = fromValue; + while (toXp >= RdDCarac.getCaracNextXp(toValue) && toXp > 0) { + toXp -= RdDCarac.getCaracNextXp(toValue); + toValue++; } - carac.xp = xp; - carac.value = value; + carac.xp = toXp; + carac.value = toValue; await this.update({ [`system.carac.${caracName}`]: carac }); - this.updateExperienceLog("Carac +", xp, caracName + " passée à " + value); + await ExperienceLog.add(this, XP_TOPIC.XPCARAC, fromXp, toXp, caracName); + await ExperienceLog.add(this, XP_TOPIC.CARAC, fromValue, toValue, caracName); } } @@ -874,17 +887,20 @@ export class RdDActor extends RdDBaseActor { async updateCompetenceXPAuto(idOrName) { let competence = this.getCompetence(idOrName); if (competence) { - let xp = Number(competence.system.xp); - let niveau = Number(competence.system.niveau); - while (xp >= RdDItemCompetence.getCompetenceNextXp(niveau) && xp > 0) { - xp -= RdDItemCompetence.getCompetenceNextXp(niveau); - niveau++; + const fromXp = Number(competence.system.xp); + const fromNiveau = Number(competence.system.niveau); + let toXp = fromXp; + let toNiveau = fromNiveau; + while (toXp >= RdDItemCompetence.getCompetenceNextXp(toNiveau) && toXp > 0) { + toXp -= RdDItemCompetence.getCompetenceNextXp(toNiveau); + toNiveau++; } await competence.update({ - "system.xp": xp, - "system.niveau": niveau, + "system.xp": toXp, + "system.niveau": toNiveau, }); - this.updateExperienceLog("Compétence +", xp, competence.name + " passée à " + niveau); + await ExperienceLog.add(this, XP_TOPIC.XP, fromXp, toXp, competence.name); + await ExperienceLog.add(this, XP_TOPIC.NIVEAU, fromNiveau, toNiveau, competence.name); } } @@ -893,29 +909,33 @@ export class RdDActor extends RdDBaseActor { if (!competence) { return; } - const stress = this.system.compteurs.experience.value; - const niveau = Number(competence.system.niveau); - const xpSuivant = RdDItemCompetence.getCompetenceNextXp(niveau); - const xpRequis = xpSuivant - competence.system.xp; - if (stress <= 0 || niveau >= competence.system.niveau_archetype) { + const fromXp = competence.system.xp; + const fromXpStress = this.system.compteurs.experience.value; + const fromNiveau = Number(competence.system.niveau); + const xpSuivant = RdDItemCompetence.getCompetenceNextXp(fromNiveau); + const xpRequis = xpSuivant - fromXp; + if (fromXpStress <= 0 || fromNiveau >= competence.system.niveau_archetype) { ui.notifications.info(`La compétence ne peut pas augmenter! - stress disponible: ${stress} + stress disponible: ${fromXpStress} expérience requise: ${xpRequis} - niveau : ${niveau} + niveau : ${fromNiveau} archétype : ${competence.system.niveau_archetype}`); return; } - const xpUtilise = Math.max(0, Math.min(stress, xpRequis)); + const xpUtilise = Math.max(0, Math.min(fromXpStress, xpRequis)); const gainNiveau = (xpUtilise >= xpRequis || xpRequis <= 0) ? 1 : 0; - const nouveauNiveau = niveau + gainNiveau; - const nouveauXp = gainNiveau > 0 ? Math.max(competence.system.xp - xpSuivant, 0) : (competence.system.xp + xpUtilise); + const toNiveau = fromNiveau + gainNiveau; + const newXp = gainNiveau > 0 ? Math.max(fromXp - xpSuivant, 0) : (fromXp + xpUtilise); await competence.update({ - "system.xp": nouveauXp, - "system.niveau": nouveauNiveau, + "system.xp": newXp, + "system.niveau": toNiveau, }); - const stressTransformeRestant = Math.max(0, stress - xpUtilise); - await this.update({ "system.compteurs.experience.value": stressTransformeRestant }); - this.updateExperienceLog('Dépense stress', xpUtilise, `Stress en ${competence.name} ${gainNiveau ? "pour passer à " + nouveauNiveau : ""}`); + const toXpStress = Math.max(0, fromXpStress - xpUtilise); + await this.update({ "system.compteurs.experience.value": toXpStress }); + + await ExperienceLog.add(this, XP_TOPIC.TRANSFORM, fromXpStress, toXpStress, `Dépense stress`); + await ExperienceLog.add(this, XP_TOPIC.XP, fromXp, newXp, competence.name); + await ExperienceLog.add(this, XP_TOPIC.NIVEAU, fromNiveau, toNiveau, competence.name); } /* -------------------------------------------- */ @@ -941,49 +961,57 @@ export class RdDActor extends RdDBaseActor { async updateCompetence(idOrName, compValue) { let competence = this.getCompetence(idOrName); if (competence) { - let nouveauNiveau = compValue ?? RdDItemCompetence.getNiveauBase(competence.system.categorie); - const tronc = RdDItemCompetence.getListTronc(competence.name).filter(it => { - const comp = this.getCompetence(it); - const niveauTr = competence ? competence.system.niveau : 0; - return niveauTr < 0 && niveauTr < nouveauNiveau; - }); - if (tronc.length > 0) { - let message = "Vous avez modifié une compétence 'tronc'. Vérifiez que les compétences suivantes évoluent ensemble jusqu'au niveau 0 : "; - for (let troncName of tronc) { - message += "
" + troncName; - } - ui.notifications.info(message); + let toNiveau = compValue ?? RdDItemCompetence.getNiveauBase(competence.system.categorie); + this.notifyCompetencesTronc(competence, toNiveau); + const fromNiveau = competence.system.niveau; + await this.updateEmbeddedDocuments('Item', [{ _id: competence.id, 'system.niveau': toNiveau }]); + await ExperienceLog.add(this, XP_TOPIC.NIVEAU, fromNiveau, toNiveau, competence.name, true); + } else { + console.log("Competence not found", idOrName); + } + } + + notifyCompetencesTronc(competence, toNiveau) { + const listTronc = RdDItemCompetence.getListTronc(competence.name).filter(it => { + const autreComp = this.getCompetence(it); + const niveauTr = autreComp?.system.niveau ?? 0; + return niveauTr < 0 && niveauTr < toNiveau; + }); + if (listTronc.length > 0) { + ui.notifications.info( + "Vous avez modifié une compétence 'tronc'. Vérifiez que les compétences suivantes évoluent ensemble jusqu'au niveau 0 :
" + + Misc.join(listTronc, '
')); + } + } + + /* -------------------------------------------- */ + async updateCompetenceXP(idOrName, toXp) { + let competence = this.getCompetence(idOrName); + if (competence) { + if (isNaN(toXp) || typeof (toXp) != 'number') toXp = 0; + const fromXp = competence.system.xp; + this.checkCompetenceXP(idOrName, toXp); + await this.updateEmbeddedDocuments('Item', [{ _id: competence.id, 'system.xp': toXp }]); + await ExperienceLog.add(this, XP_TOPIC.XP, fromXp, toXp, competence.name, true); + if (toXp > fromXp) { + RdDUtility.checkThanatosXP(idOrName); } - const update = { _id: competence.id, 'system.niveau': nouveauNiveau }; - await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity } else { console.log("Competence not found", idOrName); } } /* -------------------------------------------- */ - async updateCompetenceXP(idOrName, newXp) { + async updateCompetenceXPSort(idOrName, toXpSort) { let competence = this.getCompetence(idOrName); if (competence) { - if (isNaN(newXp) || typeof (newXp) != 'number') newXp = 0; - this.checkCompetenceXP(idOrName, newXp); - const update = { _id: competence.id, 'system.xp': newXp }; - await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity - this.updateExperienceLog("XP", newXp, "XP modifié en " + competence.name); - } else { - console.log("Competence not found", idOrName); - } - RdDUtility.checkThanatosXP(idOrName); - } - - /* -------------------------------------------- */ - async updateCompetenceXPSort(idOrName, compValue) { - let competence = this.getCompetence(idOrName); - if (competence) { - if (isNaN(compValue) || typeof (compValue) != 'number') compValue = 0; - const update = { _id: competence.id, 'system.xp_sort': compValue }; - await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity - this.updateExperienceLog("XP Sort", compValue, "XP modifié en sort de " + competence.name); + if (isNaN(toXpSort) || typeof (toXpSort) != 'number') toXpSort = 0; + const fromXpSort = competence.system.xp_sort; + await this.updateEmbeddedDocuments('Item', [{ _id: competence.id, 'system.xp_sort': toXpSort }]); + await ExperienceLog.add(this, XP_TOPIC.XPSORT, fromXpSort, toXpSort, competence.name, true); + if (toXpSort > fromXpSort) { + RdDUtility.checkThanatosXP(idOrName); + } } else { console.log("Competence not found", idOrName); } @@ -993,26 +1021,12 @@ export class RdDActor extends RdDBaseActor { async updateCompetenceArchetype(idOrName, compValue) { let competence = this.getCompetence(idOrName); if (competence) { - compValue = compValue ?? 0; - const update = { _id: competence.id, 'system.niveau_archetype': compValue }; - await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity + await this.updateEmbeddedDocuments('Item', [{ _id: competence.id, 'system.niveau_archetype': Math.max(compValue ?? 0, 0) }]); } else { console.log("Competence not found", idOrName); } } - /* -------------------------------------------- */ - async updateExperienceLog(modeXP, valeurXP, raisonXP = 'Inconnue') { - let d = new Date(); - let expLog = duplicate(this.system.experiencelog); - expLog.push({ - mode: Misc.upperFirst(modeXP), valeur: valeurXP, raison: Misc.upperFirst(raisonXP), - daterdd: game.system.rdd.calendrier.dateCourante(), - datereel: `${d.getDate()}/${d.getMonth() + 1}/${d.getFullYear()}` - }); - await this.update({ [`system.experiencelog`]: expLog }); - } - async deleteExperienceLog(from, count) { if (from >= 0 && count > 0) { let expLog = duplicate(this.system.experiencelog); @@ -1021,24 +1035,27 @@ export class RdDActor extends RdDBaseActor { } } - /* -------------------------------------------- */ - async updateCompteurValue(fieldName, fieldValue, raison = 'Inconnue') { - await this.update({ [`system.compteurs.${fieldName}.value`]: fieldValue }); - await this.addStressExperienceLog(fieldName, fieldValue, 'forcé: ' + raison); + async updateCompteurValue(fieldName, to) { + const from = this.system.compteurs[fieldName].value + await this.update({ [`system.compteurs.${fieldName}.value`]: to }); + await this.addStressExperienceLog(fieldName, from, to, fieldName, true); } /* -------------------------------------------- */ - async addCompteurValue(fieldName, fieldValue, raison = 'Inconnue') { - let oldValue = this.system.compteurs[fieldName].value; - await this.update({ [`system.compteurs.${fieldName}.value`]: Number(oldValue) + Number(fieldValue) }); - await this.addStressExperienceLog(fieldName, fieldValue, raison); + async addCompteurValue(fieldName, add, raison) { + let from = this.system.compteurs[fieldName].value; + const to = Number(from) + Number(add); + await this.update({ [`system.compteurs.${fieldName}.value`]: to }); + await this.addStressExperienceLog(fieldName, from, to, raison); } - async addStressExperienceLog(fieldName, fieldValue, raison) { - switch (fieldName) { - case 'stress': case 'experience': - await this.updateExperienceLog(fieldName, fieldValue, raison); + async addStressExperienceLog(topic, from, to, raison, manuel) { + switch (topic) { + case 'stress': + return await ExperienceLog.add(this, XP_TOPIC.STRESS, from, to, raison, manuel) + case 'experience': + return await ExperienceLog.add(this, XP_TOPIC.TRANSFORM, from, to, raison, manuel) } } @@ -1843,14 +1860,14 @@ export class RdDActor extends RdDBaseActor { /* -------------------------------------------- */ async transformerStress() { - const stress = Number(this.system.compteurs.stress.value); - if (this.system.sommeil?.insomnie || stress <= 0) { + const fromStress = Number(this.system.compteurs.stress.value); + if (this.system.sommeil?.insomnie || fromStress <= 0) { return; } const stressRoll = await this._stressRoll(this.getReveActuel()); - const conversion = Math.floor(stress * stressRoll.factor / 100); + const conversion = Math.floor(fromStress * stressRoll.factor / 100); let dissolution = Math.max(0, Number(this.system.compteurs.dissolution.value)); let exaltation = Math.max(0, Number(this.system.compteurs.exaltation.value)); const annule = Math.min(dissolution, exaltation); @@ -1862,8 +1879,8 @@ export class RdDActor extends RdDBaseActor { alias: this.name, selectedCarac: this.system.carac.reve, rolled: stressRoll, - stress: stress, - perte: Math.min(conversion, stress), + stress: fromStress, + perte: Math.min(conversion, fromStress), convertis: conversion - perteDissolution, xp: conversion - perteDissolution + exaltation, dissolution: dissolution, @@ -1875,15 +1892,18 @@ export class RdDActor extends RdDBaseActor { content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-transformer-stress.html`, stressRollData) }); + const toStress = Math.max(fromStress - stressRollData.perte - 1, 0); + const fromXpSress = Number(this.system.compteurs.experience.value); + const toXpStress = fromXpSress + Number(stressRollData.xp); const updates = { - "system.compteurs.stress.value": Math.max(stress - stressRollData.perte - 1, 0), - "system.compteurs.experience.value": Number(this.system.compteurs.experience.value) + Number(stressRollData.xp), + "system.compteurs.stress.value": toStress, + "system.compteurs.experience.value": toXpStress, "system.compteurs.dissolution.value": dissolution - perteDissolution, "system.compteurs.exaltation.value": 0 } await this.update(updates); - - this.updateExperienceLog('XP', stressRollData.xp, "Transformation du stress"); + await ExperienceLog.add(this, XP_TOPIC.STRESS, fromStress, toStress, 'Transformation') + await ExperienceLog.add(this, XP_TOPIC.TRANSFORM, fromXpSress, toXpStress, 'Transformation') } /* -------------------------------------------- */ @@ -2709,8 +2729,10 @@ export class RdDActor extends RdDBaseActor { } rollData.xpSort = RdDItemSigneDraconique.getXpSortSigneDraconique(rollData.rolled.code, rollData.signe); if (rollData.xpSort > 0) { - await this.updateEmbeddedDocuments("Item", [{ _id: compData._id, 'system.xp_sort': Misc.toInt(compData.system.xp_sort) + rollData.xpSort }]); - await this.updateExperienceLog("XP Sort", rollData.xpSort, "Signe draconique en " + rollData.competence.name); + const fromXp = Number(compData.system.xp_sort); + const toXp = fromXp + rollData.xpSort; + await this.updateEmbeddedDocuments("Item", [{ _id: compData._id, 'system.xp_sort': toXp }]); + await ExperienceLog.add(this, XP_TOPIC.XPSORT, fromXp, toXp, `${rollData.competence.name} : signe draconique`); } await this.deleteEmbeddedDocuments("Item", [rollData.signe._id]); await RdDResolutionTable.displayRollData(rollData, this.name, 'chat-resultat-lecture-signedraconique.html'); @@ -2824,11 +2846,12 @@ export class RdDActor extends RdDBaseActor { /* -------------------------------------------- */ async _xpCompetence(xpData) { if (xpData.competence) { - const newXp = Misc.toInt(xpData.competence.system.xp) + xpData.xpCompetence; - let update = { _id: xpData.competence._id, 'system.xp': newXp }; + const from = Number(xpData.competence.system.xp); + const to = from + xpData.xpCompetence; + let update = { _id: xpData.competence._id, 'system.xp': to }; await this.updateEmbeddedDocuments('Item', [update]); xpData.checkComp = await this.checkCompetenceXP(xpData.competence.name, undefined, false); - this.updateExperienceLog("XP", xpData.xpCompetence, "XP gagné en " + xpData.competence.name); + await ExperienceLog.add(this, XP_TOPIC.XP, from, to, xpData.competence.name); } } @@ -2838,10 +2861,12 @@ export class RdDActor extends RdDBaseActor { let carac = duplicate(this.system.carac); let selectedCarac = RdDActor._findCaracByName(carac, xpData.caracName); if (!selectedCarac.derivee) { - selectedCarac.xp = Misc.toInt(selectedCarac.xp) + xpData.xpCarac; + const from = Number(selectedCarac.xp); + const to = from + xpData.xpCarac; + selectedCarac.xp = to; await this.update({ "system.carac": carac }); xpData.checkCarac = await this.checkCaracXP(selectedCarac.label, false); - this.updateExperienceLog("XP", xpData.xpCarac, "XP gagné en " + xpData.caracName); + await ExperienceLog.add(this, XP_TOPIC.XPCARAC, from, to, xpData.caracName); } else { xpData.caracRepartitionManuelle = true; } diff --git a/module/actor/experience-log.js b/module/actor/experience-log.js new file mode 100644 index 00000000..2d60ed9e --- /dev/null +++ b/module/actor/experience-log.js @@ -0,0 +1,39 @@ + +export const XP_TOPIC = { + XP: { code: 'xp', label: 'xp' }, + XPSORT: { code: 'xpsort', label: 'xp sort' }, + NIVEAU: { code: 'niveau', label: 'Niveau' }, + XPCARAC: { code: 'xpcarac', label: 'xp carac' }, + CARAC: { code: 'carac', label: 'Carac' }, + STRESS: { code: 'stress', label: 'Stress' }, + TRANSFORM: { code: 'xps', label: 'Transformé' }, +} + +export class ExperienceLog { + + static async add(actor, topic, from, to, raison, manuel = false) { + if (!actor.hasPlayerOwner || !actor.isPersonnage()) { + return + } + if (from == to) { + return + } + const newXpLog = { + mode: topic?.code ?? topic, + raison: (manuel ? '(manuel) ' : '') + raison, + from: from, + to: to, + valeur: to - from, + daterdd: game.system.rdd.calendrier.dateCourante(), + datereel: game.system.rdd.calendrier.dateReel().replace('T', ' ') + }; + console.log('ExperienceLog.add', newXpLog) + const newExperienceLog = (actor.system.experiencelog ?? []).concat([newXpLog]); + await actor.update({ [`system.experiencelog`]: newExperienceLog }); + } + + static labelTopic(topic) { + const xpt = Object.values(XP_TOPIC).find(it => it.code == topic); + return xpt?.label ?? xpt?.code ?? topic; + } +} \ No newline at end of file diff --git a/module/dialog-chronologie.js b/module/dialog-chronologie.js index 911942c8..2f698056 100644 --- a/module/dialog-chronologie.js +++ b/module/dialog-chronologie.js @@ -25,23 +25,13 @@ export class DialogChronologie extends Dialog { journalId: game.settings.get(SYSTEM_RDD, LATEST_USED_JOURNAL_ID), journaux: game.journal.filter(it => it.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)), timestamp: game.system.rdd.calendrier.timestamp, - dateReel: DialogChronologie.getCurrentDateTime() + dateReel: game.system.rdd.calendrier.dateReel() }; const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-chronologie.html", dialogData); const dialog = new DialogChronologie(html, dialogData); dialog.render(true); } - static getCurrentDateTime() { - return new Date().toLocaleString("sv-SE", { - year: "numeric", - month: "2-digit", - day: "2-digit", - hour: "2-digit", - minute: "2-digit" - }).replace(" ", "T"); - } - constructor(html, dialogData) { const options = { classes: ["DialogChronologie"], @@ -124,7 +114,7 @@ export class DialogChronologie extends Dialog { heure: RdDTimestamp.definition(this.html.find("form.rdddialogchrono :input[name='chronologie.heure']").val()), minute: this.html.find("form.rdddialogchrono :input[name='chronologie.minute']").val(), }, - dateReel: this.html.find("form.rdddialogchrono :input[name='dateReel']").val().replace('T', ' ') + dateReel: this.html.find("form.rdddialogchrono :input[name='dateReel']").val() } } diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 50e47113..00c05279 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -16,6 +16,7 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDRaretes } from "./item/raretes.js"; import { RdDEmpoignade } from "./rdd-empoignade.js"; +import { ExperienceLog } from "./actor/experience-log.js"; /* -------------------------------------------- */ // This table starts at 0 -> niveau -10 @@ -136,6 +137,7 @@ export class RdDUtility { 'systems/foundryvtt-reve-de-dragon/templates/actor/blessure.hbs', 'systems/foundryvtt-reve-de-dragon/templates/actor/maladies-poisons.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/possessions.html', + 'systems/foundryvtt-reve-de-dragon/templates/actor/resonances.hbs', 'systems/foundryvtt-reve-de-dragon/templates/actor/taches.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/taches.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/oeuvres.html', @@ -283,6 +285,9 @@ export class RdDUtility { Handlebars.registerHelper('uniteQuantite', (itemId, actorId) => RdDUtility.getItem(itemId, actorId)?.getUniteQuantite()); Handlebars.registerHelper('isFieldInventaireModifiable', (type, field) => RdDItem.isFieldInventaireModifiable(type, field)); Handlebars.registerHelper('rarete-getChamp', (rarete, field) => RdDRaretes.getChamp(rarete, field)); + + Handlebars.registerHelper('experienceLog-topic', topic => ExperienceLog.labelTopic(topic)); + return loadTemplates(templatePaths); } @@ -859,17 +864,13 @@ export class RdDUtility { } /* -------------------------------------------- */ - static confirmerSuppressionSubacteur(sheet, subActor, htmlToDelete) { + static confirmerSuppressionSubacteur(sheet, subActor, htmlToDelete, onSuppression = ()=>{}) { RdDConfirm.confirmer({ settingConfirmer: "confirmation-supprimer-lien-acteur", content: `

Etes vous certain de vouloir supprimer le lien vers ${subActor.name} ?

`, title: 'Confirmer la suppression', buttonLabel: 'Supprimer le lien', - onAction: () => { - console.log('Delete : ', subActor.id); - sheet.actor.removeSubacteur(subActor.id); - RdDUtility.slideOnDelete(sheet, htmlToDelete); - } + onAction: onSuppression }) } diff --git a/module/time/rdd-calendrier.js b/module/time/rdd-calendrier.js index 11f83bbe..68aa1888 100644 --- a/module/time/rdd-calendrier.js +++ b/module/time/rdd-calendrier.js @@ -182,6 +182,16 @@ export class RdDCalendrier extends Application { return this.timestamp.formatDate(); } + dateReel() { + return new Date().toLocaleString("sv-SE", { + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit" + }); + } + isAfterIndexDate(indexDate) { // TODO: standardize return indexDate < this.timestamp.indexDate; diff --git a/module/tmr/effets-rencontres.js b/module/tmr/effets-rencontres.js index e8dee148..ec507768 100644 --- a/module/tmr/effets-rencontres.js +++ b/module/tmr/effets-rencontres.js @@ -1,3 +1,4 @@ +import { ExperienceLog, XP_TOPIC } from "../actor/experience-log.js"; import { ChatUtility } from "../chat-utility.js"; import { Poetique } from "../poetique.js"; import { RdDDice } from "../rdd-dice.js"; @@ -53,9 +54,10 @@ export class EffetsRencontre { static xp_sort_force = async (dialog, context) => { let competence = context.competence; if (competence) { - const xpSort = Misc.toInt(competence.system.xp_sort) + context.rencontre.system.force; - await this.updateEmbeddedDocuments("Item", [{ _id: compData._id, 'system.xp_sort': xpSort }]); - await this.updateExperienceLog("XP Sort", xpSort, `Rencontre d'un ${context.rencontre.name} en TMR`); + const fromXpSort = Number(competence.system.xp_sort); + const toXpSort = fromXpSort + context.rencontre.system.force; + await this.updateEmbeddedDocuments("Item", [{ _id: compData._id, 'system.xp_sort': toXpSort }]); + await ExperienceLog.add(this, XP_TOPIC.XPSORT, fromXpSort, toXpSort, `${competence.name} - ${context.rencontre.name} en TMR`); } } diff --git a/system.json b/system.json index 642ddf03..ba9bff93 100644 --- a/system.json +++ b/system.json @@ -1,8 +1,8 @@ { "id": "foundryvtt-reve-de-dragon", "title": "Rêve de Dragon", - "version": "10.7.13", - "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-10.7.13.zip", + "version": "10.7.14", + "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-10.7.14.zip", "manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v10/system.json", "compatibility": { "minimum": "10", diff --git a/templates/actor-entite-sheet.html b/templates/actor-entite-sheet.html index 5706efde..fe6c1018 100644 --- a/templates/actor-entite-sheet.html +++ b/templates/actor-entite-sheet.html @@ -41,6 +41,9 @@ {{>"systems/foundryvtt-reve-de-dragon/templates/actor/comp-creature.html"}} {{>"systems/foundryvtt-reve-de-dragon/templates/actor/comp-possession.html"}} +
+ {{>"systems/foundryvtt-reve-de-dragon/templates/actor/resonances.hbs"}} +
diff --git a/templates/actor/alchimie.html b/templates/actor/alchimie.html index 7a27fb7a..87226fe0 100644 --- a/templates/actor/alchimie.html +++ b/templates/actor/alchimie.html @@ -1,7 +1,7 @@ {{#if recettesAlchimiques.length}}

Recettes Alchimiques

diff --git a/templates/actor/hr-meditations.html b/templates/actor/hr-meditations.html index 9f7cb1d0..246a4943 100644 --- a/templates/actor/hr-meditations.html +++ b/templates/actor/hr-meditations.html @@ -1,7 +1,7 @@ {{#if meditations.length}}

Méditations