diff --git a/module/actor-sheet.js b/module/actor-sheet.js index 33e4f2c3..06db623b 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -41,7 +41,7 @@ export class RdDActorSheet extends ActorSheet { data.itemsByType = RdDItem.buildItemsClassification(data.items); // Competence per category - let competenceXPTotal = 0; + data.data.competenceXPTotal = 0; data.competenceByCategory = RdDItem.classify( data.itemsByType.competence, item => item.data.categorie, @@ -51,11 +51,10 @@ export class RdDActorSheet extends ActorSheet { //this.actor.checkCompetenceXP(item.name); // Petite vérification experience item.data.showCompetence = !data.data.showCompNiveauBase || (Number(item.data.niveau) != Number(RdDUtility.getLevelCategory(item.data.categorie))); // Ignorer les compétences 'troncs' à ce stade - competenceXPTotal += RdDItemCompetence.isTronc(item.name) ? 0 : RdDItemCompetence.computeCompetenceXPCost(item); + data.data.competenceXPTotal += RdDItemCompetence.computeCompetenceXPCost(item); return item; }); - competenceXPTotal += RdDItemCompetence.computeCompetenceTroncXP(data.itemsByType.competence); - data.data.competenceXPTotal = competenceXPTotal; + data.data.competenceXPTotal -= RdDItemCompetence.computeEconomieCompetenceTroncXP(data.itemsByType.competence); // Compute current carac sum let sum = 0; diff --git a/module/actor.js b/module/actor.js index 1e89f187..bcf27b38 100644 --- a/module/actor.js +++ b/module/actor.js @@ -2111,8 +2111,10 @@ export class RdDActor extends Actor { } } - // Notification au MJ - ChatMessage.create({ content: this.name + " est monté dans les TMR en mode : " + mode, whisper: ChatMessage.getWhisperRecipients("GM") }); + if (mode != 'visu') { + // Notification au MJ + ChatMessage.create({ content: this.name + " est monté dans les TMR en mode : " + mode, whisper: ChatMessage.getWhisperRecipients("GM") }); + } let data = { fatigue: { diff --git a/module/item-competence.js b/module/item-competence.js index 4c08b548..8bd78974 100644 --- a/module/item-competence.js +++ b/module/item-competence.js @@ -3,6 +3,20 @@ const competenceTroncs = [["Esquive", "Dague", "Corps à corps"], ["Epée à 1 main", "Epée à 2 mains", "Hache à 1 main", "Hache à 2 mains", "Lance", "Masse à 1 main", "Masse à 2 mains"]]; const competence_xp_par_niveau = [5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20, 30, 30, 40, 40, 60, 60, 100, 100, 100, 100, 100, 100, 100, 100, 100]; +const competence_niveau_max = competence_xp_par_niveau.length - 10; + +function _buildCumulXP() { + let cumulXP = { "-11": 0 }; + let cumul = 0; + for (let i = 0; i <= competence_xp_par_niveau.length; i++) { + let level = i - 10; + cumul += competence_xp_par_niveau[i]; + cumulXP[level] = cumul; + } + return cumulXP; +} + +const competence_xp_cumul = _buildCumulXP(); export class RdDItemCompetence extends Item { @@ -43,44 +57,25 @@ export class RdDItemCompetence extends Item { } /* -------------------------------------------- */ static computeCompetenceXPCost(competence) { - let minLevel = competence.data.base; - if (minLevel == competence.data.niveau) return 0; - if (competence.data.niveau < -10) return 0; - - let xp = 0; - for (let i = minLevel + 1; i <= competence.data.niveau; i++) { - xp += competence_xp_par_niveau[i + 10]; - //console.log(i, i+10, competence_xp_par_niveau[i+10]); - } - if (competence.data.categorie == 'draconic') { - xp += competence.data.xp_sort; - } + let xp = RdDItemCompetence.getDeltaXp(competence.data.base, competence.data.niveau ?? competence.data.base); + xp += competence.data.xp ?? 0; + xp += competence.data.xp_sort ?? 0; return xp; } - /* -------------------------------------------- */ - static computeCompetenceTroncXP(competences) { - let xp = 0; + static computeEconomieCompetenceTroncXP(competences) { + let economie = 0; for (let troncList of competenceTroncs) { - let minNiveau = 0; - for (let troncName of troncList) { - let comp = RdDItemCompetence.findCompetence(competences, troncName); - if (comp) { - minNiveau = Math.min(comp.data.niveau, minNiveau); - } - } - minNiveau = Math.max(minNiveau, 0); // Clamp à 0, pour le tronc commun - let minNiveauXP = competence_xp_par_niveau[minNiveau + 10]; - xp += minNiveauXP; - for (let troncName of troncList) { - let comp = RdDItemCompetence.findCompetence(competences, troncName); - if (comp) { - xp += competence_xp_par_niveau[comp.data.niveau + 10] - minNiveauXP; - } - } + let list = troncList.map(name => RdDItemCompetence.findCompetence(competences, name)) + .sort( (c1, c2) => c2.data.niveau - c1.data.niveau); // tri du plus haut au plus bas + list.splice(0,1); // ignorer la plus élevée + list.forEach(c => { + economie += RdDItemCompetence.getDeltaXp(c.data.base, Math.min(c.data.niveau, 0) ); + }); } - return xp; + return economie; } + /* -------------------------------------------- */ static findCompetence(list, name) { name = name.toLowerCase(); @@ -89,7 +84,24 @@ export class RdDItemCompetence extends Item { /* -------------------------------------------- */ static getCompetenceNextXp(niveau) { - return competence_xp_par_niveau[niveau + 10]; + return RdDItemCompetence.getCompetenceXp(niveau + 1); + } + + static getCompetenceXp(niveau) { + RdDItemCompetence._valideNiveau(niveau); + return niveau < -10 ? 0 : competence_xp_par_niveau[niveau + 10]; + } + + static getDeltaXp(from, to) { + RdDItemCompetence._valideNiveau(from); + RdDItemCompetence._valideNiveau(to); + return competence_xp_cumul[to] - competence_xp_cumul[from]; + } + + static _valideNiveau(niveau){ + if (niveau < -11 || niveau > competence_niveau_max) { + console.warn("Niveau en dehors des niveaux de compétences: [-11, " + competence_niveau_max + "]", niveau) + } } } \ No newline at end of file diff --git a/module/rdd-commands.js b/module/rdd-commands.js index c1ea3d85..a9ecde4d 100644 --- a/module/rdd-commands.js +++ b/module/rdd-commands.js @@ -2,6 +2,7 @@ import { ChatUtility } from "./chat-utility.js"; import { DeDraconique } from "./de-draconique.js"; +import { RdDItemCompetence } from "./item-competence.js"; import { Misc } from "./misc.js"; import { RdDDice } from "./rdd-dice.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js"; @@ -30,8 +31,21 @@ export class RdDCommands { rddCommands.registerCommand({ path: ["/tmra"], func: (content, msg, params) => TMRUtility.getTMRAleatoire(), descr: "Tire une case aléatoire des Terres médianes" }); rddCommands.registerCommand({ - path: ["/tmrr"], func: (content, msg, params) => rddCommands.getRencontreTMR(params), - descr: "Syntaxe: /tmrr case jet
Détermine quelle est la rencontre dans la case pour le jet
Exemple: /tmrr forêt 50" + path: ["/tmrr"], func: (content, msg, params) => rddCommands.getRencontreTMR(msg, params), + descr: "Exemple: /tmrr forêt 47
Détermine quelle est la rencontre dans une case 'forêt' pour un jet de dé de 47" + }); + + rddCommands.registerCommand({ + path: ["/xp", "comp"], func: (content, msg, params) => rddCommands.getCoutXpComp(msg, params), + descr: `Détermine le coût d'expérience pour augmenter une compétence. Exemples: +
/xp comp -6 1: pour passer de -6 à +1 +
/xp comp +4: pour atteindre le niveau 4 (depuis +3)` + }); + + rddCommands.registerCommand({ + path: ["/xp", "carac"], func: (content, msg, params) => rddCommands.getCoutXpCarac(msg, params), + descr: `Détermine le coût d'expérience pour augmenter une caractéristique. Exemples: +
/xp carac 15: coût pour atteindre 15 (depuis 14)` }); rddCommands.registerCommand({ @@ -129,8 +143,9 @@ export class RdDCommands { } } if (command && command.func) { - if (command.func(content, msg, params) === false) { - this._displayHelp(msg, `${path}: ${command.descr}`); + const result = command.func(content, msg, params); + if (result == false) { + RdDCommands._chatAnswer(msg, command.descr); } return true; } @@ -142,8 +157,13 @@ export class RdDCommands { let list = [] this._buildSubTableHelp(list, table || this.commandsTable); const messageAide = list.reduce((a, b) => a + '
  • ' + b); + RdDCommands._chatAnswer(msg, `Commandes disponibles`); + } + + /* -------------------------------------------- */ + static _chatAnswer(msg, content) { msg.whisper = [game.user._id]; - msg.content = `Commandes disponibles`; + msg.content = content; ChatMessage.create(msg); } @@ -161,7 +181,7 @@ export class RdDCommands { return list.sort(); } - + /* -------------------------------------------- */ getRencontreTMR(params) { if (params.length == 2) { return TMRUtility.getRencontre(params[0], params[1]) @@ -171,6 +191,7 @@ export class RdDCommands { } } + /* -------------------------------------------- */ async rollRdd(msg, params) { if (params.length == 0) { RdDRollResolutionTable.open(); @@ -188,6 +209,7 @@ export class RdDCommands { } } + /* -------------------------------------------- */ async rollRdDNumeric(msg, carac, diff, significative = false) { let rollData = { caracValue: carac, @@ -197,15 +219,38 @@ export class RdDCommands { show: { title: "Table de résolution" } }; await RdDResolutionTable.rollData(rollData); - msg.content = await RdDResolutionTable.buildRollDataHtml(rollData); - ChatUtility.createChatWithRollMode(game.user.name, msg); + RdDCommands._chatAnswer(msg, await RdDResolutionTable.buildRollDataHtml(rollData)); } + /* -------------------------------------------- */ async rollDeDraconique(msg) { let ddr = new DeDraconique().evaluate(); await RdDDice.show(ddr, rollMode); - msg.content = `Lancer d'un Dé draconique: ${ddr.total}`; - ChatUtility.createChatWithRollMode(game.user.name, msg); + RdDCommands._chatAnswer(msg, `Lancer d'un Dé draconique: ${ddr.total}`); } + + /* -------------------------------------------- */ + getCoutXpComp(msg, params) { + if (params && (params.length == 1 || params.length == 2)) { + let to = params.length == 1 ? Number(params[0]) : Number(params[1]); + let from = params.length == 1 ? to - 1 : Number(params[0]); + RdDCommands._chatAnswer(msg, `Coût pour passer une compétence de ${from} à ${to}: ${RdDItemCompetence.getDeltaXp(from, to)}`); + } + else { + return false; + } + } + + /* -------------------------------------------- */ + getCoutXpCarac(msg, params) { + if (params && params.length == 1) { + let to = Number(params[0]); + RdDCommands._chatAnswer(msg, `Coût pour passer une caractéristique de ${to - 1} à ${to}: ${RdDUtility.getCaractXp(to)}`); + } + else { + return false; + } + } + } diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js index 4e827961..226649ff 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -61,8 +61,9 @@ export class RdDTMRDialog extends Dialog { this.actor.santeIncDec("fatigue", this.nbFatigue).then(super.close()); // moving 1 cell costs 1 fatigue this.actor.tmrApp = undefined; // Cleanup reference this.actor.setStatusDemiReve(false); - - this._tellToGM(this.actor.name + " a quitté les terres médianes") + if (! this.viewOnly) { + this._tellToGM(this.actor.name + " a quitté les terres médianes"); + } } /* -------------------------------------------- */ diff --git a/module/rdd-utility.js b/module/rdd-utility.js index da915867..92651a28 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -405,8 +405,13 @@ export class RdDUtility { /* -------------------------------------------- */ static getCaracNextXp(value) { + const nextValue = Number(value) + 1; // xp est le coût pour atteindre cette valeur, on regarde donc le coût de la valeur+1 - return tableCaracDerivee[Number(value)+1].xp; + return RdDUtility.getCaractXp(nextValue); + } + + static getCaractXp(targetValue) { + return tableCaracDerivee[targetValue].xp; } /* -------------------------------------------- */ diff --git a/templates/actor-sheet.html b/templates/actor-sheet.html index c545c781..f3c9bcc3 100644 --- a/templates/actor-sheet.html +++ b/templates/actor-sheet.html @@ -351,8 +351,8 @@ {{else}} {{comp.name}} {{/if}} - - + +
    @@ -387,7 +387,7 @@ {{comp.name}} {{/if}} - +
    @@ -422,7 +422,7 @@ {{comp.name}} {{/if}} - +
    @@ -456,8 +456,8 @@ {{else}} {{comp.name}} {{/if}} - - + +
    @@ -492,8 +492,8 @@ {{comp.name}} {{/if}} - - + +