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..4fea285e 100644 --- a/module/rdd-resolution-table.js +++ b/module/rdd-resolution-table.js @@ -89,13 +89,22 @@ export class RdDResolutionTable { } 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; + let parts = []; + if (rollData.diffLibre != undefined) { + parts.push(`libre: ${rollData.diffLibre}`); } - return message; + 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}`); + } + let message = parts.length > 0 ? "
Difficulté " + parts.reduce((a, b) => a + ' / ' + b) : ""; + + return message+ RdDResolutionTable.explain(rollData.rolled) } /* -------------------------------------------- */ diff --git a/module/rdd-roll-resolution.js b/module/rdd-roll-resolution.js index da37e502..3f22ef46 100644 --- a/module/rdd-roll-resolution.js +++ b/module/rdd-roll-resolution.js @@ -10,16 +10,17 @@ 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 = { ajustementsConditions: CONFIG.RDD.ajustementsConditions, difficultesLibres: CONFIG.RDD.difficultesLibres, etat: 0, @@ -29,11 +30,14 @@ 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; } /* -------------------------------------------- */ 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; - } }