/** * Traveller NPC Generator - Dialogue de génération * * Ce fichier contient le dialogue pour générer des PNJ Traveller. */ import { generateAndCreateTravellerNpc } from './travellerNpcGenerator.js'; import { CITIZEN_CATEGORY_LIST, EXPERIENCE_LEVEL_LIST, ROLE_LIST, GENDER_LIST, DEFAULT_OPTIONS, generateRandomName, CITIZEN_CATEGORY_LABELS_FR, EXPERIENCE_LEVEL_LABELS_FR, ROLE_LABELS_FR, GENDER_LABELS_FR } from './data/travellerNpcGenerator.js'; const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; const MODULE_ID = 'mgt2-compendium-amiral-denisov'; export class TravellerNpcDialog extends HandlebarsApplicationMixin(ApplicationV2) { static DEFAULT_OPTIONS = { id: 'mgt2-traveller-npc', classes: ['mgt2-npc-dialog', 'mgt2-traveller-npc-dialog'], position: { width: 700, height: 'auto', }, window: { title: 'Générateur de PNJ Traveller – MgT2e', resizable: true, }, }; static PARTS = { main: { template: `modules/${MODULE_ID}/templates/traveller-npc-dialog.hbs`, root: true, }, }; constructor(options = {}) { super(options); // Form data avec valeurs par défaut this._formData = { citizenCategory: options.citizenCategory || DEFAULT_OPTIONS.citizenCategory, experience: options.experience || DEFAULT_OPTIONS.experience, role: options.role || DEFAULT_OPTIONS.role, gender: options.gender || DEFAULT_OPTIONS.gender, firstName: options.firstName || '', surname: options.surname || '', useRandomName: options.useRandomName !== false, createActor: options.createActor !== undefined ? options.createActor : DEFAULT_OPTIONS.createActor, actorName: options.actorName || '', openCreatedActor: options.openCreatedActor !== undefined ? options.openCreatedActor : DEFAULT_OPTIONS.openCreatedActor, }; // Bind les méthodes pour éviter les problèmes de contexte this._readForm = this._readForm.bind(this); this._handleGenerate = this._handleGenerate.bind(this); this._randomizeName = this._randomizeName.bind(this); this._applyThemeStyles = this._applyThemeStyles.bind(this); this._getForm = this._getForm.bind(this); } async _prepareContext() { registerHandlebarsHelpers(); return { ...this._formData, citizenCategories: CITIZEN_CATEGORY_LIST.map(c => ({ key: c.key, label: CITIZEN_CATEGORY_LABELS_FR[c.key] || c.label, description: c.description })), experienceLevels: EXPERIENCE_LEVEL_LIST.map(e => ({ key: e.key, label: EXPERIENCE_LEVEL_LABELS_FR[e.key] || e.label, description: e.description })), roles: ROLE_LIST.map(r => ({ key: r.key, label: ROLE_LABELS_FR[r.key] || r.label, description: r.description })), genders: GENDER_LIST.map(g => ({ key: g.key, label: GENDER_LABELS_FR[g.key] || g.label })) }; } async _onRender(context, options) { await super._onRender(context, options); const html = this._getForm(); if (!html?.length) return; html.addClass('mgt2-traveller-npc-form'); this._applyThemeStyles(html); // Gestion des événements html.find('[data-action="generate-traveller-npc"]').on('click', async (event) => { event.preventDefault(); this._readForm(html); await this._handleGenerate(); }); html.find('[data-action="randomize-name"]').on('click', (event) => { event.preventDefault(); this._randomizeName(html); }); // Gestion du basculement entre nom aléatoire et nom personnalisé html.find('[name="useRandomName"]').on('change', (event) => { const useRandom = event.target.checked; this._formData.useRandomName = useRandom; html.find('.name-fields').toggleClass('hidden', useRandom); }); // Initialiser l'affichage des champs de nom html.find('.name-fields').toggleClass('hidden', this._formData.useRandomName); } _getForm() { return $(this.element).find('.window-content'); } _applyThemeStyles(html) { // Les styles sont maintenant gérés par CSS, cette méthode peut être vide // ou utilisée pour des ajustements spécifiques si nécessaire // Les styles de base sont cohérents avec mgt2-npc-dialog et mgt2-commerce-dialog } _readForm(html) { this._formData.citizenCategory = html.find('[name="citizenCategory"]').val(); this._formData.experience = html.find('[name="experience"]').val(); this._formData.role = html.find('[name="role"]').val(); this._formData.gender = html.find('[name="gender"]').val(); this._formData.firstName = html.find('[name="firstName"]').val(); this._formData.surname = html.find('[name="surname"]').val(); this._formData.useRandomName = html.find('[name="useRandomName"]').is(':checked'); this._formData.createActor = html.find('[name="createActor"]').is(':checked'); this._formData.actorName = html.find('[name="actorName"]').val(); this._formData.openCreatedActor = html.find('[name="openCreatedActor"]').is(':checked'); } _randomizeName(html) { const name = generateRandomName(this._formData.gender); html.find('[name="firstName"]').val(name.firstName); html.find('[name="surname"]').val(name.surname); this._formData.firstName = name.firstName; this._formData.surname = name.surname; this._formData.useRandomName = false; html.find('[name="useRandomName"]').prop('checked', false); html.find('.name-fields').removeClass('hidden'); } async _handleGenerate() { const button = $(this.element).find('[data-action="generate-traveller-npc"]'); const originalLabel = button.html(); try { // Désactiver le bouton pendant la génération button.prop('disabled', true).html(' Génération...'); // Préparer les options de génération const generateOptions = { citizenCategory: this._formData.citizenCategory, experience: this._formData.experience, role: this._formData.role, gender: this._formData.gender, createActor: this._formData.createActor, actorName: this._formData.actorName, openCreatedActor: this._formData.openCreatedActor }; // Si on n'utilise pas de nom aléatoire, passer le nom personnalisé if (!this._formData.useRandomName && this._formData.firstName && this._formData.surname) { generateOptions.firstName = this._formData.firstName; generateOptions.surname = this._formData.surname; } // Générer le PNJ const result = await generateAndCreateTravellerNpc(generateOptions); if (result.success) { // Afficher le résultat dans le chat await this._postToChatResult(result); if (result.createdActor) { ui.notifications.info(`Fiche PNJ Traveller créée : ${result.createdActor.name}`); } } else { ui.notifications.error('Erreur lors de la génération du PNJ Traveller'); } } catch (error) { console.error(`${MODULE_ID} | Erreur lors de la génération du PNJ Traveller:`, error); ui.notifications.error(`Erreur: ${error.message}`); } finally { // Réactiver le bouton button.prop('disabled', false).html(originalLabel); } } async _postToChatResult(data) { registerHandlebarsHelpers(); const html = await foundry.applications.handlebars.renderTemplate( `modules/${MODULE_ID}/templates/traveller-npc-result.hbs`, data ); await ChatMessage.create({ content: html, speaker: ChatMessage.getSpeaker(), flags: { [MODULE_ID]: { type: 'traveller-npc-result' } }, }); } } // ============================================================================ // Helper functions // ============================================================================ // Import des données pour les helpers import { CHARACTERISTIC_LIST, UPP_ORDER } from './data/travellerNpcGenerator.js'; let helpersRegistered = false; function registerHandlebarsHelpers() { if (helpersRegistered) return; helpersRegistered = true; // Helper pour comparer deux valeurs Handlebars.registerHelper('eq', (a, b) => a === b); // Helper pour rejoindre un tableau Handlebars.registerHelper('join', (arr, sep) => (Array.isArray(arr) ? arr.join(sep) : '')); // Helper pour vérifier si une valeur contient du texte Handlebars.registerHelper('contains', (text, search) => String(text ?? '').includes(search)); // Helper pour vérifier si a > b Handlebars.registerHelper('gt', (a, b) => a > b); // Helper pour afficher le niveau de compétence avec un symbole Handlebars.registerHelper('skillLevelSymbol', (level) => { if (level === 0) return ''; if (level === 1) return '★'; if (level === 2) return '★★'; if (level === 3) return '★★★'; return `+${level}`; }); // Helper pour formater le DM Handlebars.registerHelper('formatDm', (value) => { const dm = Math.floor((value - 6) / 3); return dm >= 0 ? `+${dm}` : `${dm}`; }); // Helper pour obtenir la classe CSS du niveau de compétence Handlebars.registerHelper('skillLevelClass', (level) => { if (level === 3) return 'skill-level-3'; if (level === 2) return 'skill-level-2'; if (level === 1) return 'skill-level-1'; return 'skill-level-0'; }); // Helper pour lookup dans un objet Handlebars.registerHelper('lookup', (obj, key) => { if (!obj || !key) return ''; return obj[key] !== undefined ? obj[key] : ''; }); } // Exporter pour pouvoir l'ouvrir depuis d'autres modules export function openTravellerNpcDialog(options = {}) { new TravellerNpcDialog(options).render({ force: true }); }