feat: batch NPC import, ally/enemy gen, map sync, UI shortcuts
- batch NPC creator: import images from dir → actors (dedup, folder) - ally/enemy generator: data tables, D66 specials, tests (39 pass) - sector map sync: DialogV2 player view, socket v13/v14, sync click pos - actor/scene directory: shortcut buttons (Commerce, PNJ, Map, Sync vue) - closeImagePopout: GM closes player portraits via socket - canvasSync: force same canvas view on all players - FilePicker: v14 folder picker support with v13 fallback - cleanup: debug logs, template dedup, return guards
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
const MODULE_ID = 'mgt2-compendium-amiral-denisov';
|
||||
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
|
||||
|
||||
let _playerDialog = null;
|
||||
|
||||
class PlayerMapDialog extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
static DEFAULT_OPTIONS = {
|
||||
id: 'mgt2-sector-map-player',
|
||||
classes: ['mgt2-sector-map'],
|
||||
position: { width: 960, height: 720 },
|
||||
window: { icon: 'fas fa-map', resizable: true },
|
||||
};
|
||||
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: `modules/${MODULE_ID}/templates/player-map.hbs`,
|
||||
},
|
||||
};
|
||||
|
||||
constructor(url, sector) {
|
||||
super();
|
||||
this._mapUrl = url;
|
||||
this._sectorLabel = sector ? `Secteur ${sector}` : 'Carte stellaire';
|
||||
}
|
||||
|
||||
get title() { return this._sectorLabel; }
|
||||
|
||||
async _prepareContext() {
|
||||
return { url: this._mapUrl };
|
||||
}
|
||||
|
||||
updateMap(url) {
|
||||
this._mapUrl = url;
|
||||
const iframe = this.element?.querySelector('iframe');
|
||||
if (iframe) iframe.src = url;
|
||||
}
|
||||
}
|
||||
|
||||
function buildMapUrl(sector, subsector, mapHex, mapCenter, mapScale) {
|
||||
const base = 'https://travellermap.com';
|
||||
if (!sector) return `${base}/?style=mongoose&hideui=1`;
|
||||
if (subsector) {
|
||||
let url = `${base}/?sector=${encodeURIComponent(sector)}&subsector=${encodeURIComponent(subsector)}&style=mongoose&hideui=1`;
|
||||
if (mapCenter && mapScale) url += `¢er=${mapCenter}&scale=${mapScale}`;
|
||||
return url;
|
||||
}
|
||||
let url = `${base}/?sector=${encodeURIComponent(sector)}&style=mongoose&hideui=1`;
|
||||
if (mapHex) {
|
||||
url += `&hex=${mapHex}&scale=512`;
|
||||
} else if (mapCenter && mapScale) {
|
||||
url += `¢er=${mapCenter}&scale=${mapScale}`;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
Hooks.once('ready', () => {
|
||||
console.log(`${MODULE_ID} | sectorSocket pret`);
|
||||
|
||||
game.socket.on(`module.${MODULE_ID}`, (data) => {
|
||||
if (game.user?.isGM) return;
|
||||
|
||||
if (data?._type === 'sectorMapSync') {
|
||||
try {
|
||||
const url = buildMapUrl(data.sector, data.subsector, data.mapHex, data.mapCenter, data.mapScale);
|
||||
if (_playerDialog) {
|
||||
_playerDialog.updateMap(url);
|
||||
_playerDialog.bringToTop?.();
|
||||
console.log(`${MODULE_ID} | Carte mise a jour`);
|
||||
return;
|
||||
}
|
||||
|
||||
_playerDialog = new PlayerMapDialog(url, data.sector);
|
||||
_playerDialog.render({ force: true }).then(() => {
|
||||
console.log(`${MODULE_ID} | Dialog affiche`);
|
||||
}).catch(err => {
|
||||
console.error(`${MODULE_ID} | Erreur render:`, err);
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(`${MODULE_ID} | Erreur:`, err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (data?._type === 'canvasSync') {
|
||||
try {
|
||||
const { x, y, scale } = data;
|
||||
console.log(`${MODULE_ID} | Canvas sync recu:`, x, y, scale);
|
||||
canvas.animatePan({ x, y, scale, duration: 0 });
|
||||
} catch (err) {
|
||||
console.error(`${MODULE_ID} | Erreur canvas sync:`, err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (data?._type === 'closeImagePopout') {
|
||||
try {
|
||||
let closed = 0;
|
||||
document.querySelectorAll('.image-popout, [class*="image-popout"], [id*="image-popout"]').forEach(el => {
|
||||
el.remove(); closed++;
|
||||
});
|
||||
console.log(`${MODULE_ID} | ${closed} portrait(s) fermé(s)`);
|
||||
} catch (err) {
|
||||
console.error(`${MODULE_ID} | Erreur close portraits:`, err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user