Files
foundryvtt-wh4-lang-fr-fr/modules/inn/InnRoller.js

411 lines
15 KiB
JavaScript

/**
* 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 = `<div class="wfrp4e-inn-result">`;
message += `<div class="message-header">`;
message += `<i class="fas ${icon}"></i> `;
message += `<span class="flavor-text">${category}: ${tableName}</span>`;
message += `</div>`;
message += `<div class="inn-dish-name">${resultText}</div>`;
message += `<div class="inn-roll-info"><i class="fas fa-dice"></i> ${rollFormula} = ${rollTotal}</div>`;
message += `</div>`;
// 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 = `<div class="wfrp4e-inn-help">`;
message += `<h3><i class="fas fa-utensils"></i> Aide pour /auberge</h3>`;
message += `<p><strong>Usage:</strong> <code>/auberge [mot_clé]</code></p>`;
// Bouton Menu
message += `<div style="margin: 0.8em 0;">`;
message += `<a class="action-link inn-menu-quick-btn" data-action="clickAubergeMenu" data-quality="menu">`;
message += `<i class="fas fa-book-open"></i> Générer un menu complet`;
message += `</a>`;
message += `</div>`;
message += `<hr>`;
// Section avec liste cliquable
message += `<h4><i class="fas fa-list"></i> Tables disponibles</h4>`;
message += `<div class="wfrp4e-inn-table-grid">`;
const sortedTables = Object.values(this.tableNames).sort();
for (let tableName of sortedTables) {
const normalized = this.normalizeTableName(tableName);
const displayName = this.getDisplayName(tableName);
message += `<a class="action-link inn-table-btn" data-action="clickAuberge" data-table="${normalized}">`;
message += `<i class="fas fa-dice"></i> ${displayName}`;
message += `</a>`;
}
message += `</div>`;
message += `<hr>`;
message += `<p style="font-size: 0.9em; margin-top: 0.5em;"><em>Vous pouvez aussi taper <code>/auberge [mot_clé]</code> directement (ex: <code>/auberge base</code>)</em></p>`;
message += `</div>`;
ChatMessage.create({
content: message,
whisper: ChatMessage.getWhisperRecipients("GM")
});
}
/**
* Liste toutes les tables disponibles
*/
static listTables() {
let message = `<div class="wfrp4e-inn-list">`;
message += `<h3><i class="fas fa-list"></i> Tables d'auberge disponibles</h3>`;
message += `<div class="wfrp4e-inn-table-grid">`;
const sortedTables = Object.values(this.tableNames).sort();
for (let tableName of sortedTables) {
const normalized = this.normalizeTableName(tableName);
const displayName = this.getDisplayName(tableName);
message += `<a class="action-link inn-table-btn" data-action="clickAuberge" data-table="${normalized}">`;
message += `<i class="fas fa-dice"></i> ${displayName}`;
message += `</a>`;
}
message += `</div>`;
message += `</div>`;
ChatMessage.create({
content: message,
whisper: ChatMessage.getWhisperRecipients("GM")
});
}
/**
* Affiche le choix de qualité pour générer un menu complet
*/
static displayMenuChoice() {
let message = `<div class="wfrp4e-inn-menu-choice">`;
message += `<h3><i class="fas fa-book-open"></i> Menu de l'auberge</h3>`;
message += `<p>Choisissez la qualité du menu :</p>`;
message += `<div class="inn-menu-buttons">`;
message += `<a class="action-link inn-menu-btn" data-action="clickAubergeMenu" data-quality="mediocre">`;
message += `<i class="fas fa-drumstick-bite"></i> Menu Médiocre`;
message += `<br><span class="inn-menu-desc">Plat médiocre + Boisson de base</span>`;
message += `</a>`;
message += `<a class="action-link inn-menu-btn" data-action="clickAubergeMenu" data-quality="commun">`;
message += `<i class="fas fa-utensils"></i> Menu Commun`;
message += `<br><span class="inn-menu-desc">Plat commun + Boisson de base + Dessert</span>`;
message += `</a>`;
message += `<a class="action-link inn-menu-btn" data-action="clickAubergeMenu" data-quality="qualite">`;
message += `<i class="fas fa-crown"></i> Menu de Qualité`;
message += `<br><span class="inn-menu-desc">Plat de qualité + Boisson forte + Dessert</span>`;
message += `</a>`;
message += `<a class="action-link inn-menu-btn" data-action="clickAubergeMenu" data-quality="fluvial">`;
message += `<i class="fas fa-fish"></i> Menu Fluvial`;
message += `<br><span class="inn-menu-desc">Plat de rivière + Boisson de base + Dessert</span>`;
message += `</a>`;
message += `<a class="action-link inn-menu-btn" data-action="clickAubergeMenu" data-quality="maritime">`;
message += `<i class="fas fa-anchor"></i> Menu Maritime`;
message += `<br><span class="inn-menu-desc">Plat maritime + Boisson forte + Dessert</span>`;
message += `</a>`;
message += `<a class="action-link inn-menu-btn" data-action="clickAubergeMenu" data-quality="excellent">`;
message += `<i class="fas fa-gem"></i> Menu Excellent`;
message += `<br><span class="inn-menu-desc">Plat excellent + Boisson forte + Dessert</span>`;
message += `</a>`;
message += `</div>`;
message += `</div>`;
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 = `<div class="wfrp4e-inn-menu-result">`;
message += `<div class="message-header">`;
message += `<i class="fas fa-book-open"></i> `;
message += `<span class="flavor-text">${menuName}</span>`;
message += `</div>`;
message += `<div class="inn-menu-items">`;
for (let result of results) {
message += `<div class="inn-menu-item">`;
let icon = result.category === 'Boisson' ? 'fa-wine-glass' :
result.category === 'Dessert' ? 'fa-birthday-cake' : 'fa-utensils';
message += `<i class="fas ${icon}"></i> `;
message += `<strong>${result.category}:</strong> ${result.name}`;
message += `</div>`;
}
message += `</div>`;
message += `</div>`;
await ChatMessage.create({
content: message,
speaker: ChatMessage.getSpeaker(),
whisper: ChatMessage.getWhisperRecipients("GM")
});
}
}