Files
mgt2-compendium-amiral-denisov/scripts/npc.js
T
uberwald 76870c27bf Corrections, styles et traductions FR pour /gennpc - v1.3.0
Corrections critiques implémentées:
- Remplacement du cache global mutable par ModuleCache
- Binding des méthodes dans TravellerNpcDialog
- Suppression des ré-exports circulaires
- Validation complète des options
- Correction: Duplicate export de TravellerNpcDialog et openTravellerNpcDialog
- Correction: distributeSkillLevels ne supprime plus les spécialisations
  (ex: Pilot-Spacecraft ET Pilot-Small Craft sont maintenant conservées)

Améliorations majeures:
- Optimisation de l'algorithme de distribution des compétences (single-pass)
- Optimisation de la génération des caractéristiques (priorité-based)
- Gestion d'erreur améliorée avec TravellerNpcError
- Création de TravellerNpcUtils.js avec classes utilitaires

Améliorations mineures:
- CSS aligné avec les styles des dialogues /commerce et /pnj
- Thème clair cohérent (#f5f0e8 background, #222 text)
- Fieldset, onglets, formulaires alignés sur mgt2-npc-form
- Boutons et résultats stylisés comme mgt2-npc-result
- Suppression des styles inline redondants dans _applyThemeStyles
- Design réactif, accessibilité, impression
- Tests unitaires complets pour toutes les fonctions

Traductions en français:
- Ajout de SKILL_LABELS_FR pour toutes les compétences Traveller
- Ajout de CHARACTERISTIC_LABELS_FR pour STR, DEX, END, INT, EDU, SOC
- Ajout de CITIZEN_CATEGORY_LABELS_FR, EXPERIENCE_LEVEL_LABELS_FR
- Ajout de ROLE_LABELS_FR, GENDER_LABELS_FR
- Mise à jour de generateTravellerNpc pour utiliser les libellés français
- Mise à jour du template traveller-npc-result.hbs pour afficher labelFr
- Mise à jour du template traveller-npc-dialog.hbs avec libellés français
- Mise à jour de TravellerNpcDialog._prepareContext pour utiliser les libellés FR

Vérification des compétences:
 Pilot: 13 compétences (avant: 12, perdait Pilot-Small Craft)
 Engineer: 13 compétences (avant: 10, perdait 3 spécialisations)
 Tous les rôles conservent leurs spécialisations

Fichiers ajoutés:
- scripts/utils/travellerNpcUtils.js
- scripts/tests/travellerNpcGenerator.test.js

Fichiers modifiés:
- scripts/data/travellerNpcGenerator.js (+ traductions FR)
- scripts/travellerNpcGenerator.js (+ fonctions getSkillLabelFr, getCharacteristicLabelFr)
- scripts/TravellerNpcDialog.js (libellés FR dans _prepareContext)
- scripts/npc.js
- styles/traveller-npc.css
- templates/traveller-npc-dialog.hbs
- templates/traveller-npc-result.hbs
- module.json

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-05-28 00:03:44 +02:00

195 lines
6.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { NpcDialog } from './NpcDialog.js';
import { openTravellerNpcDialog } from './TravellerNpcDialog.js';
import { syncNpcRollTables } from './npcRollTableSync.js';
import './mgt2eMigration.js';
const MODULE_ID = 'mgt2-compendium-amiral-denisov';
const ChatLogV2 = foundry.applications.sidebar.tabs.ChatLog;
function openNpcDialog(initialTab, options = {}) {
new NpcDialog({ initialTab, ...options }).render({ force: true });
}
function openTravellerNpcGenerator() {
openTravellerNpcDialog();
}
function registerNpcCommand(commandName, initialTab) {
if (!ChatLogV2?.CHAT_COMMANDS) {
console.warn(`${MODULE_ID} | ChatLog.CHAT_COMMANDS indisponible, commande /${commandName} non enregistrée`);
return;
}
ChatLogV2.CHAT_COMMANDS[commandName] = {
rgx: new RegExp(`^\\/${commandName}(?:\\s+(.*))?$`, 'i'),
fn: () => {
openNpcDialog(initialTab);
return false;
},
};
console.log(`${MODULE_ID} | Commande /${commandName} enregistrée via ChatLog.CHAT_COMMANDS`);
}
function registerTravellerNpcCommand() {
if (!ChatLogV2?.CHAT_COMMANDS) {
console.warn(`${MODULE_ID} | ChatLog.CHAT_COMMANDS indisponible, commande /gennpc non enregistrée`);
return;
}
ChatLogV2.CHAT_COMMANDS.gennpc = {
rgx: new RegExp(`^\\/gennpc(?:\\s+(.*))?$`, 'i'),
fn: () => {
openTravellerNpcGenerator();
return false;
},
};
console.log(`${MODULE_ID} | Commande /gennpc enregistrée via ChatLog.CHAT_COMMANDS`);
}
Hooks.once('init', () => {
console.log(`${MODULE_ID} | Outils PNJ initialisés`);
// Pré-charge les templates Handlebars
// Compatibilité v13 et v14
const loadTemplatesFn = foundry.applications?.handlebars?.loadTemplates || loadTemplates;
if (loadTemplatesFn) {
loadTemplatesFn([
`modules/${MODULE_ID}/templates/npc-dialog.hbs`,
`modules/${MODULE_ID}/templates/npc-result.hbs`,
`modules/${MODULE_ID}/templates/traveller-npc-dialog.hbs`,
`modules/${MODULE_ID}/templates/traveller-npc-result.hbs`,
]);
}
registerNpcCommand('pnj', 'npc');
registerNpcCommand('rencontre', 'encounter');
registerNpcCommand('mission', 'mission');
registerTravellerNpcCommand();
});
Hooks.once('ready', async () => {
await syncNpcRollTables();
console.log(`${MODULE_ID} | Outils PNJ prêts tapez /pnj, /rencontre, /mission ou /gennpc dans le chat`);
});
/**
* Solution pour Foundry v14 : Intercepte les commandes AVANT la validation
* Utilise renderChatInput pour modifier le comportement de l'input
* Compatible v13 (jQuery) et v14 (DOM element)
*/
Hooks.on('renderChatInput', (app, html, data) => {
// Foundry v14 passe un objet avec element, v13 passe jQuery
let input;
// Vérifie si html est un objet avec element (v14)
if (html?.element) {
input = $(html.element).find('textarea[name="content"]');
} else if (html?.find) {
// v13 ou déjà jQuery
input = html.find('textarea[name="content"]');
} else {
// Dernier recours : suppose que html est l'élément
input = $(html).find('textarea[name="content"]');
}
// Évite les doublons d'écouteurs
if (input.data('mgt2-npc-listener')) return;
input.data('mgt2-npc-listener', true);
input.on('keydown', (event) => {
// Intercepte Entrée (13) et vérifie si c'est une de nos commandes
if (event.key === 'Enter' && !event.shiftKey) {
const content = input.val()?.trim();
if (content?.startsWith('/pnj')) {
event.preventDefault();
event.stopImmediatePropagation();
openNpcDialog('npc');
input.val('');
} else if (content?.startsWith('/rencontre')) {
event.preventDefault();
event.stopImmediatePropagation();
openNpcDialog('encounter');
input.val('');
} else if (content?.startsWith('/mission')) {
event.preventDefault();
event.stopImmediatePropagation();
openNpcDialog('mission');
input.val('');
} else if (content?.startsWith('/gennpc')) {
event.preventDefault();
event.stopImmediatePropagation();
openTravellerNpcGenerator();
input.val('');
}
}
});
});
/**
* Intercepte les messages de chat pour /pnj, /rencontre, /mission, /gennpc
* Utilise preCreateChatMessage pour Foundry v14+ (avant que le message ne soit validé)
* Compatible avec Foundry v13 et v14
*/
Hooks.on('preCreateChatMessage', (message, data, options) => {
const content = message.content?.trim()?.toLowerCase();
if (content === '/pnj' || content?.startsWith('/pnj ')) {
openNpcDialog('npc');
return false; // Empêche la création du message
}
if (content === '/rencontre' || content?.startsWith('/rencontre ')) {
openNpcDialog('encounter');
return false; // Empêche la création du message
}
if (content === '/mission' || content?.startsWith('/mission ')) {
openNpcDialog('mission');
return false; // Empêche la création du message
}
if (content === '/gennpc' || content?.startsWith('/gennpc ')) {
openTravellerNpcGenerator();
return false; // Empêche la création du message
}
});
// Gardé pour compatibilité v13
Hooks.on('chatMessage', (...args) => {
// Foundry v14 passe un objet ChatMessage en premier paramètre
// Foundry v13 passe (chatLog, message, chatData)
let message;
if (args[0]?.content !== undefined) {
// v14: premier argument est ChatMessage
message = args[0].content;
} else if (typeof args[1] === 'string') {
// v13: deuxième argument est la string message
message = args[1];
} else {
return;
}
const trimmed = message?.trim()?.toLowerCase();
if (trimmed === '/pnj' || trimmed?.startsWith('/pnj ')) {
openNpcDialog('npc');
return false;
}
if (trimmed === '/rencontre' || trimmed?.startsWith('/rencontre ')) {
openNpcDialog('encounter');
return false;
}
if (trimmed === '/mission' || trimmed?.startsWith('/mission ')) {
openNpcDialog('mission');
return false;
}
if (trimmed === '/gennpc' || trimmed?.startsWith('/gennpc ')) {
openTravellerNpcGenerator();
return false;
}
});