/** * InnRoller * Classe de gestion des jets de tables d'auberge pour WFRP4e * Module de traduction française */ export default class InnRoller { static tableNames = { 'boissonsbase': 'BoissonsBase', 'boissonsfortes': 'BoissonsFortes', 'desserts': 'Desserts', 'platscommuns': 'PlatsCommuns', 'platsexcellents': 'PlatsExcellents', 'platsmaritimes': 'PlatsMaritimes', 'platsmediocres': 'PlatsMédiocres', 'platsqualite': 'PlatsQualité', 'platsrivieres': 'PlatsRivières' }; static displayNames = { 'BoissonsBase': 'Boissons de Base', 'BoissonsFortes': 'Boissons Fortes', 'Desserts': 'Desserts', 'PlatsCommuns': 'Plats Communs', 'PlatsExcellents': 'Plats Excellents', 'PlatsMaritimes': 'Plats Maritimes', 'PlatsMédiocres': 'Plats Médiocres', 'PlatsQualité': 'Plats de Qualité', 'PlatsRivières': 'Plats de Rivières' }; /** * Obtient le nom d'affichage formaté pour une table * @param {String} tableName * @returns {String} */ static getDisplayName(tableName) { return this.displayNames[tableName] || tableName; } /** * Normalise le nom d'une table (enlève accents, espaces, met en minuscules) * @param {String} name * @returns {String} */ static normalizeTableName(name) { return name .toLowerCase() .normalize("NFD") .replace(/[\u0300-\u036f]/g, "") .replace(/\s+/g, ''); } /** * Trouve la table correspondant au mot-clé * @param {String} keyword * @returns {String|null} */ static findTableByKeyword(keyword) { if (!keyword) return null; const normalized = this.normalizeTableName(keyword); // Recherche exacte if (this.tableNames[normalized]) { return this.tableNames[normalized]; } // Recherche partielle for (let [key, value] of Object.entries(this.tableNames)) { if (key.includes(normalized) || normalized.includes(key)) { return value; } } return null; } /** * Lance un jet sur une table d'auberge * @param {String} keyword Mot-clé pour identifier la table */ static async rollInnTable(keyword) { console.log(`InnRoller: rollInnTable appelé avec keyword="${keyword}"`); // Si pas de keyword, afficher l'aide if (!keyword) { this.displayHelp(); return; } // Rechercher la table const tableName = this.findTableByKeyword(keyword); if (!tableName) { this.displayHelp(); ui.notifications.warn(`Table d'auberge introuvable pour le mot-clé: "${keyword}"`); return; } console.log(`InnRoller: Table trouvée: ${tableName}`); // Charger le compendium const compendium = game.packs.get('wh4-fr-translation.plats-dauberges'); if (!compendium) { ui.notifications.error("Compendium 'plats-dauberges' introuvable"); console.error("InnRoller: Compendium wh4-fr-translation.plats-dauberges non trouvé"); return; } // Récupérer les tables const tables = await compendium.getDocuments(); // Trouver la table correspondante const rollTable = tables.find(t => t.name === tableName); if (!rollTable) { ui.notifications.error(`Table "${tableName}" non trouvée dans le compendium`); console.error(`InnRoller: Table ${tableName} non trouvée`); return; } console.log(`InnRoller: Jet sur la table ${rollTable.name}`); // Effectuer le jet sans affichage automatique try { const roll = await rollTable.draw({ displayChat: false }); console.log(`InnRoller: Jet effectué avec succès`, roll); // Créer un message personnalisé await this.displayRollResult(rollTable.name, roll); } catch (error) { console.error("InnRoller: Erreur lors du jet:", error); ui.notifications.error("Erreur lors du jet sur la table d'auberge"); } } /** * Affiche le résultat d'un jet de table avec un style personnalisé * @param {String} tableName Nom de la table * @param {Object} rollResult Résultat du jet */ static async displayRollResult(tableName, rollResult) { // Déterminer l'icône en fonction du type de table let icon = "fa-utensils"; let category = "Plat"; if (tableName.toLowerCase().includes('boisson')) { icon = "fa-wine-glass"; category = "Boisson"; } else if (tableName.toLowerCase().includes('dessert')) { icon = "fa-birthday-cake"; category = "Dessert"; } // Extraire les informations du résultat const resultText = rollResult.results[0]?.text || "Résultat inconnu"; const rollFormula = rollResult.roll?.formula || "1d100"; const rollTotal = rollResult.roll?.total || 0; // Construire le message HTML simplifié let message = `
`; message += `
`; message += ` `; message += `${category}: ${tableName}`; message += `
`; message += `
${resultText}
`; message += `
${rollFormula} = ${rollTotal}
`; message += `
`; // Créer le message dans le chat await ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker(), whisper: ChatMessage.getWhisperRecipients("GM") }); } /** * Affiche l'aide pour la commande /auberge avec liste cliquable */ static displayHelp() { let message = `
`; message += `

Aide pour /auberge

`; message += `

Usage: /auberge [mot_clé]

`; // Bouton Menu message += `
`; message += ``; message += ` Générer un menu complet`; message += ``; message += `
`; message += `
`; // Section avec liste cliquable message += `

Tables disponibles

`; message += `
`; const sortedTables = Object.values(this.tableNames).sort(); for (let tableName of sortedTables) { const normalized = this.normalizeTableName(tableName); const displayName = this.getDisplayName(tableName); message += ``; message += ` ${displayName}`; message += ``; } message += `
`; message += `
`; message += `

Vous pouvez aussi taper /auberge [mot_clé] directement (ex: /auberge base)

`; message += `
`; ChatMessage.create({ content: message, whisper: ChatMessage.getWhisperRecipients("GM") }); } /** * Liste toutes les tables disponibles */ static listTables() { let message = `
`; message += `

Tables d'auberge disponibles

`; message += `
`; const sortedTables = Object.values(this.tableNames).sort(); for (let tableName of sortedTables) { const normalized = this.normalizeTableName(tableName); const displayName = this.getDisplayName(tableName); message += ``; message += ` ${displayName}`; message += ``; } message += `
`; message += `
`; ChatMessage.create({ content: message, whisper: ChatMessage.getWhisperRecipients("GM") }); } /** * Affiche le choix de qualité pour générer un menu complet */ static displayMenuChoice() { let message = `
`; message += `

Menu de l'auberge

`; message += `

Choisissez la qualité du menu :

`; message += `
`; message += ``; message += ` Menu Médiocre`; message += `
Plat médiocre + Boisson de base`; message += `
`; message += ``; message += ` Menu Commun`; message += `
Plat commun + Boisson de base + Dessert`; message += `
`; message += ``; message += ` Menu de Qualité`; message += `
Plat de qualité + Boisson forte + Dessert`; message += `
`; message += ``; message += ` Menu Fluvial`; message += `
Plat de rivière + Boisson de base + Dessert`; message += `
`; message += ``; message += ` Menu Maritime`; message += `
Plat maritime + Boisson forte + Dessert`; message += `
`; message += ``; message += ` Menu Excellent`; message += `
Plat excellent + Boisson forte + Dessert`; message += `
`; message += `
`; message += `
`; ChatMessage.create({ content: message, whisper: ChatMessage.getWhisperRecipients("GM") }); } /** * Génère un menu complet selon la qualité choisie * @param {String} quality - 'mediocre', 'commun', ou 'qualite' */ static async generateMenu(quality) { console.log(`InnRoller: generateMenu appelé avec quality="${quality}"`); let tables = []; let menuName = ""; // Définir les tables à tirer selon la qualité switch(quality) { case 'mediocre': menuName = "Menu Médiocre"; tables = ['PlatsMédiocres', 'BoissonsBase']; break; case 'commun': menuName = "Menu Commun"; tables = ['PlatsCommuns', 'BoissonsBase', 'Desserts']; break; case 'qualite': menuName = "Menu de Qualité"; tables = ['PlatsQualité', 'BoissonsFortes', 'Desserts']; break; case 'fluvial': menuName = "Menu Fluvial"; tables = ['PlatsRivières', 'BoissonsBase', 'Desserts']; break; case 'maritime': menuName = "Menu Maritime"; tables = ['PlatsMaritimes', 'BoissonsFortes', 'Desserts']; break; case 'excellent': menuName = "Menu Excellent"; tables = ['PlatsExcellents', 'BoissonsFortes', 'Desserts']; break; default: ui.notifications.error(`Qualité de menu inconnue: ${quality}`); return; } // Charger le compendium const compendium = game.packs.get('wh4-fr-translation.plats-dauberges'); if (!compendium) { ui.notifications.error("Compendium 'plats-dauberges' introuvable"); return; } const allTables = await compendium.getDocuments(); let results = []; // Effectuer les jets sur chaque table for (let tableName of tables) { const rollTable = allTables.find(t => t.name === tableName); if (rollTable) { try { const roll = await rollTable.draw({ displayChat: false }); const resultText = roll.results[0]?.text || "Résultat inconnu"; results.push({ category: this.getCategoryName(tableName), name: resultText, tableName: tableName }); } catch (error) { console.error(`InnRoller: Erreur lors du jet sur ${tableName}:`, error); } } } // Afficher le menu complet this.displayMenuResult(menuName, results); } /** * Obtient le nom de catégorie pour une table * @param {String} tableName * @returns {String} */ static getCategoryName(tableName) { if (tableName.includes('Boisson')) return 'Boisson'; if (tableName.includes('Dessert')) return 'Dessert'; if (tableName.includes('Plat')) return 'Plat'; return 'Item'; } /** * Affiche le résultat d'un menu complet * @param {String} menuName * @param {Array} results */ static async displayMenuResult(menuName, results) { let message = `
`; message += `
`; message += ` `; message += `${menuName}`; message += `
`; message += `
`; for (let result of results) { message += `
`; let icon = result.category === 'Boisson' ? 'fa-wine-glass' : result.category === 'Dessert' ? 'fa-birthday-cake' : 'fa-utensils'; message += ` `; message += `${result.category}: ${result.name}`; message += `
`; } message += `
`; message += `
`; await ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker(), whisper: ChatMessage.getWhisperRecipients("GM") }); } }