diff --git a/module/actor.js b/module/actor.js index a824d6d2..8fbe1f0c 100644 --- a/module/actor.js +++ b/module/actor.js @@ -517,7 +517,7 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async sortMisEnReserve(rollData, sort) { let reserve = duplicate(this.data.data.reve.reserve); - reserve.list.push({ coord: rollData.coord, sort: sort, draconic: duplicate(rollData.selectedDraconic) }); + reserve.list.push({ coord: rollData.coord, sort: sort, draconic: duplicate(rollData.competence) }); await this.update({ "data.reve.reserve": reserve }); this.currentTMR.updateSortReserve(); } @@ -1290,14 +1290,14 @@ export class RdDActor extends Actor { createCallbackExperience() { return { condition: r => r.rolled.isPart && r.finalLevel < 0 && game.settings.get("core", "rollMode") != 'selfroll', - action: r => this._appliquerAjoutExperience(r) + action: r => this._appliquerAjoutExperience(r, game.settings.get("core", "rollMode") != 'blindroll') }; } /* -------------------------------------------- */ - async _appliquerAjoutExperience(rollData) { - let xpResult = this.appliquerExperience( rollData.rolled, rollData.selectedCarac.label, (rollData.competence) ? rollData.competence.data.name: undefined ); - if (xpResult.result ) { + async _appliquerAjoutExperience(rollData, display=true) { + let xpResult = this.appliquerExperience( rollData.rolled, rollData.selectedCarac.label, rollData.competence); + if (display && xpResult.result ) { let xpmsg = "
Points d'expérience gagnés ! Carac: " + xpResult.xpCarac + ", Comp: " + xpResult.xpCompetence; let message = ChatUtility.prepareChatMessage('gmroll', this.name); message.content = "" + rollData.selectedCarac.label + "" @@ -1319,7 +1319,7 @@ export class RdDActor extends Actor { selectedCarac: this.data.data.carac.reve, draconicList: this.getDraconicList(), sortList: sortList, - selectedDraconic: this.getBestDraconic(), + competence: this.getBestDraconic(), selectedSort: sortList[0], coord: coord, coordLabel: TMRUtility.getTMRDescription( coord).label, @@ -1447,82 +1447,67 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async _rollUnSortResult(rollData, isSortReserve = false) { - rollData.isSortReserve = isSortReserve; let rolled = rollData.rolled; - let sort = rollData.selectedSort; - let closeTMR = !rollData.isSortReserve; - if (sort.data.isrituel && isSortReserve) { - ui.notifications.error("Impossible de mettre le rituel '" + sort.name + "' en réserve"); + let selectedSort = rollData.selectedSort; + let closeTMR = !isSortReserve; + if (selectedSort.data.isrituel && isSortReserve) { + ui.notifications.error("Impossible de mettre le rituel '" + selectedSort.name + "' en réserve"); this.currentTMR.close(); // Close TMR ! return; - } + } + + rollData.isSortReserve = isSortReserve; + rollData.show = {} + rollData.depenseReve = Number(selectedSort.data.ptreve_reel); - let explications = rollData.isSortReserve - ? ("
Mise en réserve du sort en " + rollData.coordLabel + "(" + rollData.coord + ")") - : "
Lancement du sort "; - explications += sort.name + " : " + Misc.upperFirst(sort.data.draconic) - + " pour " + sort.data.ptreve_reel + " points de Rêve" - + "
Depuis la case " + rollData.coord + " (" + TMRUtility.getTMRDescription(rollData.coord).label + ")"; - - let depenseReve = Number(sort.data.ptreve_reel); let myReve = duplicate(this.data.data.reve.reve); if (rolled.isSuccess) { // Réussite du sort ! - //sort.ptreve_reel = coutReve; if (rolled.isPart) { - depenseReve = Math.max(Math.floor(depenseReve / 2), 1); + rollData.depenseReve = Math.max(Math.floor(rollData.depenseReve / 2), 1); } if (rollData.isSortReserve) { - depenseReve++; + rollData.depenseReve++; } - if (myReve.value > depenseReve) { - explications += "
Réussite du sort: " + depenseReve + " points de Rêve sont dépensés (Bonus de case en " + rollData.coord + ": +" + rolled.bonus + "%)"; - + if (myReve.value > rollData.depenseReve) { // Incrémenter/gére le bonus de case - RdDItemSort.incrementBonusCase(this, sort, rollData.coord); - + RdDItemSort.incrementBonusCase(this, selectedSort, rollData.coord); + if (rollData.isSortReserve) { - await this.sortMisEnReserve(rollData, sort); + await this.sortMisEnReserve(rollData, selectedSort); closeTMR = false; } } else { - // Todo 0 pts de reve !!!! - depenseReve = 0; - explications += "
Pas assez de rêve"; - mergeObject(rollData, RdDResolutionTable.getResultat("echec")); + rollData.depenseReve = 0; + rollData.show.reveInsuffisant = true; + mergeObject(rollData.rolled, RdDResolutionTable.getResultat("echec"), {overwrite:true}); } } else { if (rolled.isETotal) { // Echec total ! - depenseReve = Math.min(myReve.value, Math.floor(depenseReve * 1.5)); - explications += "
Echec TOTAL du sort : " + depenseReve + " Points de Rêve"; + rollData.depenseReve = Math.min(myReve.value, Math.floor(rollData.depenseReve * 1.5)) // TODO: mise en réserve d'un échec total... } else { - depenseReve = 0 - explications += "
Echec du sort !"; + rollData.depenseReve = 0 } } - myReve.value = Math.max(myReve.value - depenseReve, 0); + myReve.value = Math.max(myReve.value - rollData.depenseReve, 0); await this.update({ "data.reve.reve": myReve }); - if (myReve.value == 0) { // 0 points de reve - ChatMessage.create({ content: this.name + " est réduit à 0 Points de Rêve, et tombe endormi !" }); - closeTMR = true; - } if (closeTMR) { this.currentTMR.close(); // Close TMR ! } else { this.currentTMR.maximize(); // Re-display TMR } // Final chat message - let chatOptions = { - content: "Test : " + rollData.selectedCarac.label + " / " + rollData.selectedDraconic.name + " / " + rollData.selectedSort.name + "" - + RdDResolutionTable.explainRollData(rollData) - + explications - } - + let chatOptions = { content: await RdDResolutionTable.explainRollDataV2(rollData, 'chat-resultat-sort.html') } ChatUtility.chatWithRollMode(chatOptions, this.name) + + if (myReve.value == 0) { // 0 points de reve + ChatMessage.create({ content: this.name + " est réduit à 0 Points de Rêve, et tombe endormi !" }); + closeTMR = true; + } } /* -------------------------------------------- */ @@ -1548,17 +1533,12 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async _rollCaracResult(rollData) { - let rolled = rollData.rolled; - - let resumeCompetence = (rollData.diffLibre + rollData.diffConditions); - let explications = "
Points de taches : " + rolled.ptTache; - + rollData.show = { + title: rollData.selectedCarac.label, + points: true + }; // Final chat message - let chatOptions = { - content: "Test : " + rollData.selectedCarac.label + " / " + resumeCompetence + "" - + RdDResolutionTable.explainRollData(rollData) - + explications - } + let chatOptions = { content: await RdDResolutionTable.explainRollDataV2(rollData) } ChatUtility.chatWithRollMode(chatOptions, this.name) } @@ -1740,7 +1720,7 @@ export class RdDActor extends Actor { } /* -------------------------------------------- */ - async appliquerExperience( rolled, caracName, competenceName = undefined ) { + async appliquerExperience( rolled, caracName, competence = undefined ) { if ( rolled.isPart && rolled.finalLevel < 0) { // Cas de désir lancinant, pas d'expérience sur particulière @@ -1751,37 +1731,38 @@ export class RdDActor extends Actor { } if (caracName == 'derobee') caracName = 'agilite'; - let carac = duplicate(this.actor.data.data.carac); - let xp = Math.abs(rolled.finalLevel); let xpCarac = Math.floor(xp / 2); // impair: arrondi inférieur en carac - let xpComp = 0; - if ( competenceName ) { + if ( competence ) { xpComp = xp - xpCarac; - let competence = duplicate( RdDUtility.findCompetence( this.data.items, competenceName ) ); - competence.data.xp += xpComp; + competence = duplicate(competence ); + competence.data.xp = Misc.toInt(competence.data.xp) + xpComp; await this.updateEmbeddedEntity( "OwnedItem", competence); } else { xpCarac = Math.max(xpCarac, 1); } - if ( !carac[caracName].isderivee) { - carac[caracName].xp += xpCarac; - await this.update( {"data.carac": carac } ); - } else { - ChatMessage.create( { content: `Vous avez ${xpCarac} à répartir pour la caractérisque dérivée ${caracName}. Vous devez le faire manuellement.`, - whisper: ChatMessage.getWhisperRecipients(game.user.name) } ); + if (xpCarac > 0) { + let carac = duplicate(this.data.data.carac); + let selectedCarac = RdDActor._findCaracByName(carac, caracName); + if ( !selectedCarac.derivee) { + selectedCarac.xp = Misc.toInt(selectedCarac.xp) + xpCarac; + await this.update( {"data.carac": carac } ); + } else { + ChatMessage.create( { content: `Vous avez ${xpCarac} à répartir pour la caractérisque dérivée ${caracName}. Vous devez le faire manuellement.`, + whisper: ChatMessage.getWhisperRecipients(game.user.name) } ); + } } return { result:true, xpcarac:xpCarac, xpCompetence: xpComp }; //XP } - return { result:false, xpcarac:0, xpCompetence: 0 }; // Pas d'XP } /* -------------------------------------------- */ async ajouteNombreAstral( data ) { // Gestion expérience (si existante) - this.appliquerExperience( data.rolled, "vue", "astrologie"); + let astrologie = RdDUtility.findCompetence( this.data.items, "astrologie"); + this.appliquerExperience( data.rolled, "vue", astrologie); // Ajout du nombre astral const item = {name: "Nombre Astral", type: "nombreastral", data: @@ -1808,23 +1789,39 @@ export class RdDActor extends Actor { getCaracByName(caracName) { switch (caracName) { - case 'reve-actuel': + case 'reve-actuel': case 'Rêve actuel': return { - label: 'Rêve Actuel', + label: 'Rêve actuel', value: this.getReveActuel(), type: "number", ignoreEtatGeneral: true }; - case 'chance-actuelle': + case 'chance-actuelle': case 'Chance actuelle': return { - type: "number", - value: this.getChanceActuel(), label: 'Chance actuelle', + value: this.getChanceActuel(), + type: "number", ignoreEtatGeneral: true }; - default: - return this.data.data.carac[caracName]; // Per default } + return RdDActor._findCaracByName(this.data.data.carac, caracName); + } + + static _findCaracByName(carac, name) { + name = name.toLowerCase(); + switch (name) + { + case 'reve-actuel': case 'rêve actuel': + return carac.reve; + case 'chance-actuelle': case 'chance actuelle': + return carac.chance; + } + for (const [key, value] of Object.entries(carac)) { + if (name == key || name == value.label.toLowerCase()) { + return carac[key]; + } + } + return carac[name]; // Per default } /* -------------------------------------------- */ diff --git a/module/rdd-commands.js b/module/rdd-commands.js new file mode 100644 index 00000000..409ae4ee --- /dev/null +++ b/module/rdd-commands.js @@ -0,0 +1,185 @@ +/* -------------------------------------------- */ + +import { ChatUtility } from "./chat-utility.js"; +import { Misc } from "./misc.js"; +import { RdDResolutionTable } from "./rdd-resolution-table.js"; +import { RdDRollResolution } from "./rdd-roll-resolution.js"; +import { RdDRollTables } from "./rdd-rolltables.js"; +import { RdDUtility } from "./rdd-utility.js"; +import { TMRUtility } from "./tmr-utility.js"; + +const rddRollNumeric = /(\d+)\s*([\+\-]?\d+)?\s*(s)?/; + +/* -------------------------------------------- */ +export class RdDCommands { + + static init() { + if (!game.system.rdd.commands) { + const rddCommands = new RdDCommands(); + rddCommands.registerCommand({ path: ["/aide"], descr: "Affiche l'aide pour toutes les commandes", func: (content, msg, params) => rddCommands.help(msg) }); + rddCommands.registerCommand({ path: ["/help"], descr: "Affiche l'aide pour toutes les commandes", func: (content, msg, params) => rddCommands.help(msg) }); + rddCommands.registerCommand({ path: ["/table", "queues"], descr: "Tire une Queue de Dragon", func: (content, msg, params) => RdDRollTables.getQueue() }); + rddCommands.registerCommand({ path: ["/table", "ombre"], descr: "Tire une Ombre de Dragon", func: (content, msg, params) => RdDRollTables.getOmbre() }); + rddCommands.registerCommand({ path: ["/table", "tetehr"], descr: "Tire une Tête de Dragon pour Hauts Revants", func: (content, msg, params) => RdDRollTables.getTeteHR() }); + rddCommands.registerCommand({ path: ["/table", "tete"], descr: "Tire une Tête de Dragon", func: (content, msg, params) => RdDRollTables.getTete() }); + rddCommands.registerCommand({ path: ["/table", "souffle"], descr: " Tire un Souffle de Dragon", func: (content, msg, params) => RdDRollTables.getSouffle() }); + rddCommands.registerCommand({ path: ["/table", "tarot"], descr: "Tire une carte du Tarot Draconique", func: (content, msg, params) => RdDRollTables.getTarot() }); + rddCommands.registerCommand({ path: ["/table", "tmr"], descr: "Tire une case aléatoire des Terre médiane", func: (content, msg, params) => TMRUtility.getTMRAleatoire() }); + + rddCommands.registerCommand({ path: ["/tmra"], descr: "Tire une case aléatoire des Terre médiane", func: (content, msg, params) => TMRUtility.getTMRAleatoire() }); + rddCommands.registerCommand({ path: ["/tmrr"], descr: "Syntaxe: /tmrr case jet
Détermine quelle est la rencontre dans la case pour le jet
Example: /tmrr forêt 50", func: (content, msg, params) => rddCommands.getRencontreTMR(params) }); + rddCommands.registerCommand({ + path: ["/rdd"], descr: `Effectue un jet de dés dans la table de résolution. Examples: +
/rdd ouvre la table de résolution +
/rdd 10 3 effectue un jet 10 à +3 +
/rdd 10 +2 effectue un jet 10 à +2 +
/rdd 15 -2 effectue un jet 15 à -2 +
/rdd 15 0 s effectue un jet 15 à 0, avec significative requise + `, func: (content, msg, params) => rddCommands.rollRdd(msg, params) + }); + + rddCommands.registerCommand({ path: ["/payer"], descr: `Permet de payer un montant. Exemples: +
/payer 5s 10d permet d'envoyer un message pour payer 5 sols et 10 deniers +
/payer 10d permet d'envoyer un message pour payer 10 deniers + `, func: (content, msg, params) => RdDUtility.afficherDemandePayer(params[0], params[1])}); + game.system.rdd.commands = rddCommands; + } + } + + constructor() { + this.commandsTable = {}; + } + + registerCommand(command) { + this._addCommand(this.commandsTable, command.path, command); + } + + _addCommand(targetTable, path, command) { + if (!this._validateCommand(targetTable, path, command)) { + return; + } + const term = path[0]; + if (path.length == 1) { + targetTable[term] = command; + } + else { + if (!targetTable[term]) { + targetTable[term] = { subTable: {} }; + } + this._addCommand(targetTable[term].subTable, path.slice(1), command) + } + } + + _validateCommand(targetTable, path, command) { + if (path.length > 0 && path[0] && command.descr && (path.length != 1 || targetTable[path[0]] == undefined)) { + return true; + } + console.warn("RdDCommands._validateCommand failed ", targetTable, path, command); + return false; + } + + + /* -------------------------------------------- */ + /* Manage chat commands */ + processChatCommand(commandLine, content, msg) { + // Setup new message's visibility + let rollMode = game.settings.get("core", "rollMode"); + if (["gmroll", "blindroll"].includes(rollMode)) msg["whisper"] = ChatMessage.getWhisperRecipients("GM"); + if (rollMode === "blindroll") msg["blind"] = true; + msg["type"] = 0; + + let command = commandLine[0]; + let params = commandLine.slice(1); + + return this.process(command, params, content, msg); + } + + process(command, params, content, msg) { + return this._processCommand(this.commandsTable, command, params, content, msg); + } + + _processCommand(commandsTable, name, params, content = '', msg = {}, path = "") { + let command = commandsTable[name]; + path = path + name + " "; + if (command && command.subTable) { + if (params[0]) { + return this._processCommand(command.subTable, params[0], params.slice(1), content, msg, path) + } + else { + this.help(msg, command.subTable); + return true; + } + } + if (command && command.func) { + if (command.func(content, msg, params) === false) { + this._displayHelp(msg, `${path}: ${command.descr}`); + } + return true; + } + return false; + } + + /* -------------------------------------------- */ + help(msg, table = undefined) { + let list = [] + this._buildSubTableHelp(list, '', table || this.commandsTable); + msg.whisper = [game.user._id]; + msg.content = 'Commandes disponibles'; + ChatMessage.create(msg); + } + + /* -------------------------------------------- */ + _buildSubTableHelp(list, path, table) { + for (let [name, command] of Object.entries(table)) { + if (command) { + if (command.subTable) { + this._buildSubTableHelp(list, path + name + " ", command.subTable); + } else { + list.push(`${path}${name}: ${command.descr}`); + } + } + } + return list; + } + + + getRencontreTMR(params) { + if (params.length == 2) { + return TMRUtility.getRencontre(params[0], params[1]) + } + else { + return false; + } + } + + async rollRdd(msg, params) { + if (params.length == 0) { + RdDRollResolution.open(); + } + else { + let flatParams = params.reduce((a, b) => `${a} ${b}`); + const numericParams = flatParams.match(rddRollNumeric); + if (numericParams) { + const carac = Misc.toInt(numericParams[1]); + const diff = Misc.toInt(numericParams[2] || 0); + const significative = numericParams[3] == 's' + await this.rollRdDNumeric(msg, carac, diff, significative); + return; + } + } + } + + async rollRdDNumeric(msg, carac, diff, significative = false) { + let rollData = { + caracValue: carac, + finalLevel: diff, + showDice: true, + needSignificative: significative, + show: { title: "Table de résolution", points: true } + }; + await RdDResolutionTable.rollData(rollData); + msg.content = await RdDResolutionTable.explainRollDataV2(rollData); + ChatUtility.chatWithRollMode(msg, game.user.name); + } +} + diff --git a/module/rdd-main.js b/module/rdd-main.js index a6be6ccb..8ef650e9 100644 --- a/module/rdd-main.js +++ b/module/rdd-main.js @@ -19,6 +19,7 @@ import { TMRUtility } from "./tmr-utility.js"; import { RdDCalendrier } from "./rdd-calendrier.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDTokenHud } from "./rdd-token-hud.js"; +import { RdDCommands } from "./rdd-commands.js"; /* -------------------------------------------- */ /* Foundry VTT Initialization */ @@ -212,14 +213,15 @@ Hooks.once("init", async function() { /* -------------------------------------------- */ function messageDeBienvenue(){ game.messages - .filter(it => it.user._id == game.user._id && it.data.content.match(/^Bienvenu(e)? dans le Rêve des Dragons/)) + .filter(it => it.user._id == game.user._id && it.data.content.match(/^
" + - "Vous trouverez quelques informations pour démarrer dans ce document : @Compendium[foundryvtt-reve-de-dragon.rappel-des-regles.7uGrUHGdPu0EmIu2]{Documentation MJ/Joueurs}" } - ); + content : `
Bienvenue dans le Rêve des Dragons ! +
Vous trouverez quelques informations pour démarrer dans ce document : @Compendium[foundryvtt-reve-de-dragon.rappel-des-regles.7uGrUHGdPu0EmIu2]{Documentation MJ/Joueurs} +
La commande /aide dans le chat permet de voir les commandes spécifiques à Rêve de Dragon.
+ ` }); } /* -------------------------------------------- */ @@ -232,6 +234,8 @@ Hooks.once("renderApplication", () => { /* -------------------------------------------- */ Hooks.once("ready", function() { + // préparation des lignes de commandes + RdDCommands.init(); /* -------------------------------------------- */ /* Affiche/Init le calendrier */ let calendrier = new RdDCalendrier(); @@ -271,11 +275,15 @@ Hooks.on("preCreateToken", (scene, tokenData, options) => { /* Foundry VTT Initialization */ /* -------------------------------------------- */ Hooks.on("chatMessage", (html, content, msg) => { - let regExp = /(\S+)/g; - let commands = content.match(regExp); - - return RdDUtility.processChatCommand( commands, content, msg ); -} ); + if (content[0] == '/') { + let regExp = /(\S+)/g; + let commands = content.toLowerCase().match(regExp); + if (game.system.rdd.commands.processChatCommand(commands, content, msg)){ + return false; + } + } + return true; +}); /* -------------------------------------------- */ Hooks.on("getCombatTrackerEntryContext", (html, options) => { diff --git a/module/rdd-resolution-table.js b/module/rdd-resolution-table.js index b65ad195..e9cd6f05 100644 --- a/module/rdd-resolution-table.js +++ b/module/rdd-resolution-table.js @@ -70,7 +70,7 @@ export class RdDResolutionTable { /* -------------------------------------------- */ static getResultat(code) { - let resultat = reussites.filter(r => code == r.code); + let resultat = reussites.find(r => code == r.code); if (resultat == undefined) { resultat = reussites.find(r => r.code == "error"); } @@ -88,14 +88,64 @@ export class RdDResolutionTable { return message; } - static explainRollData(rollData) { - let message = "
Difficultés libre: " + rollData.diffLibre + " / conditions: " + Misc.toSignedString(rollData.diffConditions) - + " / état: " + rollData.etat; - message += RdDResolutionTable.explain(rollData.rolled) - if (rollData.selectedCarac == rollData.carac.volonte) { - message += " / moral: " + rollData.moral; + static async explainRollDataV2(rollData, template = 'chat-resultat-rdd.html') { + rollData.ajustements = RdDResolutionTable._buildAjustements(rollData); + rollData.show = rollData.show || {}; + + let html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/${template}`, rollData); + return html; + } + + static _buildAjustements(rollData) { + let list = []; + if (rollData.competence) { + list.push({ label: rollData.competence.name, value: rollData.competence.data.niveau}); } - return message; + if (rollData.diffLibre != undefined) { + const label = rollData.selectedSort ? rollData.selectedSort.name : 'libre'; + list.push({ label: label, value: rollData.diffLibre }); + } + if (rollData.diffConditions != undefined) { + list.push({ label: 'conditions', value: rollData.diffConditions }); + } + if (rollData.etat != undefined) { + list.push({ label: 'état', value: rollData.etat }); + } + if (rollData.selectedCarac != undefined && rollData.moral != undefined && rollData.selectedCarac.label == 'Volonté') { + list.push({ label: 'moral', value: rollData.selectedCarac != undefined && rollData.moral != undefined && rollData.selectedCarac.label == 'Volonté' ? rollData.moral : undefined }); + } + if (RdDResolutionTable.isAjustementAstrologique(rollData)) { + list.push({ label: 'astrologique', value: rollData.ajustementAstrologique||0 }); + } + if (rollData.rolled.bonus && rollData.selectedSort) { + list.push({ label: 'Bonus de case', value: rollData.rolled.bonus, unit: '%' }); + } + return list; + } + + static explainRollData(rollData) { + let parts = RdDResolutionTable._buildAjustementsList(rollData); + let message = parts.length > 0 ? "
Difficulté " + parts.reduce((a, b) => a + ' / ' + b) : ""; + + return message+ RdDResolutionTable.explain(rollData.rolled) + } + + + static _buildAjustementsList(rollData) { + let parts = []; + if (rollData.diffLibre != undefined) { + parts.push(`libre: ${rollData.diffLibre}`); + } + if (rollData.diffConditions != undefined) { + parts.push(`conditions: ${Misc.toSignedString(rollData.diffConditions)}`); + } + if (rollData.etat != undefined) { + parts.push(`état: ${rollData.etat}`); + } + if (rollData.selectedCarac != undefined && rollData.moral != undefined && rollData.selectedCarac.label == 'Volonté') { + parts.push(`moral: ${rollData.moral}`); + } + return parts; } /* -------------------------------------------- */ @@ -156,6 +206,16 @@ export class RdDResolutionTable { return duplicate(this.resolutionTable[caracValue][difficulte + 10]); } + static isAjustementAstrologique(rollData) { + if (rollData.selectedCarac && rollData.selectedCarac.label.toLowerCase().includes('chance')) { + return true; + } + if (rollData.selectedSort && rollData.selectedSort.data.isrituel) { + return true; + } + return false; + } + /* -------------------------------------------- */ static isEchec(rollData) { switch (rollData.surprise) { diff --git a/module/rdd-roll-resolution.js b/module/rdd-roll-resolution.js index da37e502..ceb7073d 100644 --- a/module/rdd-roll-resolution.js +++ b/module/rdd-roll-resolution.js @@ -2,6 +2,7 @@ import { ChatUtility } from "./chat-utility.js"; import { Misc } from "./misc.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js"; +const titleTableDeResolution = 'Table de résolution'; /** * Extend the base Dialog entity to select roll parameters * @extends {Dialog} @@ -10,16 +11,18 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js"; export class RdDRollResolution extends Dialog { /* -------------------------------------------- */ - static async open() { - let rollData = RdDRollResolution._prepareDefaultOptions(); + static async open(rollData = {selectedCarac:10}) { + RdDRollResolution._setDefaultOptions(rollData); let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-roll-resolution.html', rollData); const dialog = new RdDRollResolution(rollData, html); dialog.render(true); } /* -------------------------------------------- */ - static _prepareDefaultOptions() { - let rollData = { + static _setDefaultOptions(rollData) { + + let defRollData = { + show: {title: titleTableDeResolution, points:true}, ajustementsConditions: CONFIG.RDD.ajustementsConditions, difficultesLibres: CONFIG.RDD.difficultesLibres, etat: 0, @@ -29,18 +32,19 @@ export class RdDRollResolution extends Dialog { diffConditions: 0, diffLibre: 0 } + mergeObject(rollData, defRollData, {overwrite: false}); for (let i = 1; i < 21; i++) { rollData.carac[i] = { type: "number", value: i, label: i } + if (rollData.selectedCarac == i) { + rollData.selectedCarac = rollData.carac[i]; + } } - rollData.selectedCarac = rollData.carac[10]; - return rollData; } /* -------------------------------------------- */ constructor(rollData, html) { - let conf = { - title: 'Lancer les dés', + title: titleTableDeResolution, content: html, buttons: { 'lancer': { label: 'Lancer les dés', callback: html => this.onAction(html) } @@ -55,9 +59,7 @@ export class RdDRollResolution extends Dialog { async onAction(html) { await RdDResolutionTable.rollData(this.rollData); console.log("RdDRollResolution -=>", this.rollData, this.rollData.rolled); - const message = { - content: "Table de résolution: " + RdDResolutionTable.explainRollData(this.rollData) - }; + const message = { content: await RdDResolutionTable.explainRollDataV2(this.rollData)}; ChatUtility.chatWithRollMode(message, game.user.name) } @@ -117,9 +119,4 @@ export class RdDRollResolution extends Dialog { _computeDiffLibre(rollData) { return Misc.toInt(rollData.diffLibre); } - - /* -------------------------------------------- */ - _getTitle(rollData) { - return 'Table de résolution'; - } } diff --git a/module/rdd-roll.js b/module/rdd-roll.js index 1d24f6b9..8230efe2 100644 --- a/module/rdd-roll.js +++ b/module/rdd-roll.js @@ -121,7 +121,7 @@ export class RdDRoll extends Dialog { HtmlUtility._showControlWhen($(".diffMoral"), rollData.selectedCarac == actor.data.data.carac.volonte); HtmlUtility._showControlWhen($("#etat-general"), !dialog._isIgnoreEtatGeneral(rollData)); - HtmlUtility._showControlWhen($("#ajust-astrologique"), dialog._isAjustementAstrologique(rollData)); + HtmlUtility._showControlWhen($("#ajust-astrologique"), RdDResolutionTable.isAjustementAstrologique(rollData)); // Sort management if (rollData.selectedSort) { @@ -176,7 +176,7 @@ export class RdDRoll extends Dialog { }); html.find('#draconic').change((event) => { let draconicKey = Misc.toInt(event.currentTarget.value); - this.rollData.selectedDraconic = rollData.draconicList[draconicKey]; // Update the selectedCarac + this.rollData.competence = rollData.draconicList[draconicKey]; // Update the selectedCarac //console.log("RdDRollSelectDialog","CARAC CLICKED !!!", rollData); updateRollResult(rollData); }); @@ -229,7 +229,7 @@ export class RdDRoll extends Dialog { const malusEnc = (rollData.surencMalusApply) ? rollData.surencMalusValue : 0; const bonusTactique = RdDBonus.bonusAttaque(rollData.tactique); const malusEncTotal = (rollData.useMalusEncTotal) ? -rollData.encTotal : 0; - const ajustementChance = this._isAjustementAstrologique(rollData) ? rollData.ajustementAstrologique : 0; + const ajustementChance = RdDResolutionTable.isAjustementAstrologique(rollData) ? rollData.ajustementAstrologique : 0; // Gestion malus armure const malusArmureValue = this._computeMalusArmure(rollData); @@ -240,22 +240,12 @@ export class RdDRoll extends Dialog { return etat + diffCompetence + diffLibre + diffMoral + diffConditions + malusEnc + malusEncTotal + malusArmureValue + ajustementChance + bonusTactique; } - _isAjustementAstrologique(rollData) { - if (rollData.selectedCarac.label.toLowerCase().includes('chance')) { - return true; - } - if (rollData.selectedSort && rollData.selectedSort.data.isrituel) { - return true; - } - return false; - } - _computeDiffCompetence(rollData) { if (rollData.competence) { return Misc.toInt(rollData.competence.data.niveau); } if (rollData.draconicList) { - return Misc.toInt(rollData.selectedDraconic.data.niveau); + return Misc.toInt(rollData.competence.data.niveau); } return 0; } @@ -288,7 +278,7 @@ export class RdDRoll extends Dialog { return rollData.selectedCarac.label + "/" + rollData.competence.name + armeTitle + " " + niveau } if (rollData.draconicList) { - return rollData.selectedDraconic.name + " - " + rollData.selectedSort.name; + return rollData.competence.name + " - " + rollData.selectedSort.name; } return rollData.selectedCarac.label; } diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js index 134665d5..8bebbf2d 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -145,7 +145,7 @@ export class RdDTMRDialog extends Dialog { /* -------------------------------------------- */ async gererTourbillon( value ) { - this.nbFatigue += value; + this.nbFatigue += 1; await this.actor.reveActuelIncDec( -value ); if ( !this.currentRencontre.tourbillonDirection ) { this.currentRencontre.tourbillonDirection = TMRUtility.getDirectionPattern(); @@ -158,7 +158,7 @@ export class RdDTMRDialog extends Dialog { /* -------------------------------------------- */ async gererTourbillonRouge( ) { - this.nbFatigue += 4; // 4 cases -> 4 pts de fatigue + this.nbFatigue += 1; await this.actor.reveActuelIncDec( -2 ); // -2 pts de Reve a chaque itération if ( !this.currentRencontre.tourbillonDirection ) { this.currentRencontre.tourbillonDirection = TMRUtility.getDirectionPattern(); diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 46031101..bab53c0d 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -891,17 +891,6 @@ export class RdDUtility { }); } - /* -------------------------------------------- */ - /* Display help for /table */ - static displayHelpTable( msg ) - { - msg.content = ""; - for (let [name, tableData] of Object.entries(table2func)) { - msg.content += "
" + tableData.descr; - } - ChatMessage.create( msg ); - } - /* -------------------------------------------- */ static afficherDemandePayer(som1, som2) { som1 = (som1) ? som1.toLowerCase() : "0d"; @@ -922,38 +911,4 @@ export class RdDUtility { msgPayer += "Payer" ChatMessage.create( { content: msgPayer } ); } - - /* -------------------------------------------- */ - /* Manage chat commands */ - static processChatCommand( commands, content, msg ) { - // Setup new message's visibility - let rollMode = game.settings.get("core", "rollMode"); - if (["gmroll", "blindroll"].includes(rollMode)) msg["whisper"] = ChatMessage.getWhisperRecipients("GM"); - if (rollMode === "blindroll") msg["blind"] = true; - msg["type"] = 0; - - let command = commands[0]; - - // Roll on a table - if (command === "/table") { - if ( commands[1] ) { - let tableName = commands[1].toLowerCase(); - table2func[tableName].func(); - } else { - this.displayHelpTable( msg ); - } - return false - } else if (command === "/tmrr") { - TMRUtility.getRencontre(commands[1], commands[2] ) - return false - } else if (command === "/tmra") { - TMRUtility.getTMRAleatoire( ) - return false - } else if (command === "/payer") { - RdDUtility.afficherDemandePayer( commands[1], commands[2] ) - return false - } - - return true; - } } diff --git a/styles/simple.css b/styles/simple.css index 71bfe4f6..e190cb0d 100644 --- a/styles/simple.css +++ b/styles/simple.css @@ -86,6 +86,9 @@ margin: 0; padding: 0; } +.strong-text{ + font-weight: bold; +} .tabs .item.active, .blessures-list li ul li:first-child:hover, a:hover { text-shadow: 1px 0px 0px #ff6600; @@ -364,6 +367,35 @@ table {border: 1px solid #7a7971;} z-index: 9999; display: block; } +.rdd-roll-part{ + align-items: center; + border-radius: 6px; padding: 3px; + background:linear-gradient(30deg, rgba(191, 149, 63, 0.3), rgba(252, 246, 186, 0.3), rgba(179, 135, 40, 0.3), rgba(251, 245, 183, 0.3), rgba(170, 119, 28, 0.3)); +} +.rdd-roll-sign{ + border-radius: 6px; padding: 3px; + background:linear-gradient(30deg, rgba(61, 55, 93, 0.3), rgba(178, 179, 196, 0.3), rgba(59, 62, 63, 0.6), rgba(206, 204, 199, 0.3), rgba(61, 46, 49, 0.3)); +} +.rdd-roll-norm{ + border-radius: 6px; padding: 3px; + background:linear-gradient(30deg, rgba(7, 76, 0, 0.3), rgba(66, 163, 65, 0.2), rgba(184, 226, 163, 0.1), rgba(66, 163, 65, 0.2), rgba(184, 226, 163, 0.3)); +} +.rdd-roll-echec{ + border-radius: 6px; padding: 3px; + background-image: linear-gradient(150deg, rgba(255, 0, 0, 0.3), rgba(255, 200, 128, 0.05),rgba(255, 200, 128, 0.1), rgba(255,10,0,0.3)); +} +.rdd-roll-epart{ + border-radius: 6px; padding: 3px; + background:linear-gradient(150deg, rgba(100, 45, 124, 0.6), rgba(216, 157, 192, 0.3), rgba(177, 157, 216, 0.5), rgba(107, 62, 121, 0.3), rgba(100, 45, 124, 0.6)); +} +.rdd-roll-etotal{ + border-radius: 6px; padding: 3px; + background:linear-gradient(150deg, rgba(0, 0, 0, 0.7), rgba(100, 45, 124, 0.4), rgba(82, 17, 131, 0.3),rgba(100, 45, 124, 0.4), rgba(0, 0, 0, 0.7)); +} +.rdd-need-significative{ + border-radius: 6px; padding: 3px; + background:linear-gradient(30deg, rgba(61, 55, 93, 0.2), rgba(178, 179, 196, 0.1), rgba(59, 62, 63, 0.2), rgba(206, 204, 199, 0.1), rgba(61, 46, 49, 0.2)); +} .table-resolution-carac { background-color: yellow; @@ -1180,22 +1212,25 @@ display: inline-flex; /* Tooltip text */ .tooltip .tooltiptext { visibility: hidden; - width: 360px; - background-color: rgba(30, 25, 20, 0.9); text-align: center; padding: 5px 0; border-radius: 6px; - + /* Position the tooltip text */ position: absolute; z-index: 1; - top: 30px; - left: -30%; - + /* Fade in tooltip */ opacity: 0; transition: opacity 0.3s; +} +.tooltiptext-fatigue{ + width: 360px; + top: 30px; + left: -30%; + + background-color: rgba(30, 25, 20, 0.9); border-image: url(img/ui/bg_control.jpg) 21 repeat; border-image-slice: 6 6 6 6 fill; border-image-width: 6px 6px 6px 6px; @@ -1203,6 +1238,13 @@ display: inline-flex; border-radius: 0px; } +.tooltiptext-ajustements { + width: 150px; + top: 30px; + background: rgba(220,220,210,0.9); + font-size: 0.8rem; +} + /* Show the tooltip text when you mouse over the tooltip container */ .tooltip:hover .tooltiptext { visibility: visible; diff --git a/templates/actor-sheet.html b/templates/actor-sheet.html index e7805231..5efded6b 100644 --- a/templates/actor-sheet.html +++ b/templates/actor-sheet.html @@ -31,7 +31,7 @@
Malus de fatigue : {{data.fatigue.malus}} - {{{data.fatigue.html}}} + {{{data.fatigue.html}}} {{data.blessures.resume}}
diff --git a/templates/chat-resultat-rdd.html b/templates/chat-resultat-rdd.html new file mode 100644 index 00000000..4f7344ce --- /dev/null +++ b/templates/chat-resultat-rdd.html @@ -0,0 +1,30 @@ +

+ {{#if show.title}}{{show.title}}: {{/if}} + + {{rolled.caracValue}} à {{numberFormat rolled.finalLevel decimals=0 sign=true}} + {{#if ajustements}} +
+
Ajustements
+ {{#each ajustements as |item key|}} +
{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}{{#if item.unit}}{{item.unit}}{{/if}}
+ {{/each}} +
+ {{/if}} +
+ {{#if rolled.needSignificative}}{{/if}} = + {{rolled.score}}% +

+
+ {{rolled.roll}} : + {{rolled.quality}} +
+{{#if show.points}} +
+ {{rolled.ptTache}} points de tâche{{#if rolled.ptQualite}}, ajustement Qualité {{numberFormat rolled.ptQualite decimals=0 sign=true}}{{/if}} +
+{{/if}} +{{~#if show.explications}} +
+ {{show.explications}} +
+{{/if}} diff --git a/templates/chat-resultat-sort.html b/templates/chat-resultat-sort.html new file mode 100644 index 00000000..8da601a7 --- /dev/null +++ b/templates/chat-resultat-sort.html @@ -0,0 +1,40 @@ +

+ {{#if isSortReserve}}Mise en réserve{{else}}Lancement{{/if}} du sort {{selectedSort.name}} r{{selectedSort.data.ptreve_reel}} +
+ + {{competence.name}}: {{rolled.caracValue}} à {{numberFormat rolled.finalLevel decimals=0 sign=true}} +
+
Ajustements
+ {{#each ajustements as |item key|}} +
{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}{{#if item.unit}}{{item.unit}}{{/if}}
+ {{/each}} +
+
+ {{#if rolled.needSignificative}}{{/if}} = + {{rolled.score}}% +

+
Pour {{selectedSort.data.ptreve_reel}} points de rêve en {{coordLabel}} ({{coord}})
+
+
+ {{rolled.roll}} : + {{rolled.quality}} + {{#if show.reveInsuffisant}}Pas assez de rêve!{{/if}} + + {{#if rolled.isETotal}} + Echec TOTAL du sort! + {{else if rolled.isEchec}} + Echec du sort, + {{else}} + Réussite du sort, + {{/if~}} + + + {{#if (eq depenseReve 0)}} + pas de dépense de rêve + {{else if (eq depenseReve 1)}} + 1 point de rêve a été dépensé + {{else}} + {{depenseReve}} points de rêve ont été dépensés + {{/if}} + +
\ No newline at end of file diff --git a/templates/dialog-tmr.html b/templates/dialog-tmr.html index 2c9e09ee..a266ccfa 100644 --- a/templates/dialog-tmr.html +++ b/templates/dialog-tmr.html @@ -12,7 +12,7 @@
- 0 + 0
0