import { RdDItem } from '../item.js'; import { HtmlUtility } from '../html-utility.js'; import { Misc } from "../misc.js"; import { CompendiumTableHelpers } from '../settings/system-compendiums.js'; import { RdDRaretes } from '../item/raretes.js'; import { Grammar } from '../grammar.js'; const FILTER_GROUPS = [ { group: 'type', label: "Type d'objet" }, { group: 'comestible', label: 'Alimentaire' }, { group: 'utilisation', label: 'Utilisation' }, { group: 'rarete', label: 'Rarete' }, { group: 'qualite', label: 'Qualité' }, { group: 'enc', label: 'Encombrement' }, { group: 'prix', label: 'Prix' }, ] const FILTERS = [ { group: 'comestible', code: 'comestible', label: 'Comestible', check: (item, milieux) => item.getUtilisation() == 'cuisine' }, { group: 'comestible', code: 'pret', label: 'Préparé', check: (item, milieux) => item.getUtilisationCuisine() == 'pret' }, { group: 'comestible', code: 'brut', label: 'A préparer', check: (item, milieux) => item.getUtilisationCuisine() == 'brut' }, { group: 'comestible', code: 'boisson', label: 'Boisson', check: (item, milieux) => item.isBoisson() }, { group: 'comestible', code: 'alcool', label: 'Alcool', check: (item, milieux) => item.isAlcool() }, { group: 'comestible', code: 'immangeable', label: 'Immangeable', check: (item, milieux) => item.isInventaire() && item.getUtilisation() != 'cuisine' }, { group: 'utilisation', code: 'alchimie', label: 'Alchimique', check: (item, milieux) => item.isInventaire() && item.getUtilisation() == 'alchimie' }, { group: 'utilisation', code: 'soins', label: 'Médical', check: (item, milieux) => item.isInventaire() && item.getUtilisation() == 'soins' }, { group: 'utilisation', code: 'poison', label: 'Toxique', check: (item, milieux) => item.isInventaire() && item.getUtilisation() == 'poison' }, { group: 'utilisation', code: 'cuisine', label: 'Cuisine', check: (item, milieux) => item.isInventaire() && item.getUtilisation() == 'cuisine' }, { group: 'utilisation', code: 'autres', label: 'Autres/inconnu', check: (item, milieux) => !item.isInventaire() || item.getUtilisation() == '' }, { group: "qualite", code: "mauvaise", label: "Mauvaise (négative)", check: (item, milieux) => item.isInventaire() && item.system.qualite < 0 }, { group: "qualite", code: "quelconque", label: "Quelconque (0)", check: (item, milieux) => item.isInventaire() && item.system.qualite == 0 }, { group: "qualite", code: "correcte", label: "Correcte (1-3)", check: (item, milieux) => item.isInventaire() && 1 <= item.system.qualite && item.system.qualite <= 3 }, { group: "qualite", code: "bonne", label: "Bonne (4-6)", check: (item, milieux) => item.isInventaire() && 4 <= item.system.qualite && item.system.qualite <= 6 }, { group: "qualite", code: "excellente", label: "Excellente (7-9)", check: (item, milieux) => item.isInventaire() && 7 <= item.system.qualite && item.system.qualite <= 9 }, { group: "qualite", code: "mythique", label: "Mythique (10+)", check: (item, milieux) => item.isInventaire() && 10 <= item.system.qualite }, { group: "enc", code: "negligeable", label: "Négligeable (jusqu'à 0.1)", check: (item, milieux) => item.isInventaire() && item.system.encombrement <= 0.1 }, { group: "enc", code: "leger", label: "Léger (0.1 à 0.5)", check: (item, milieux) => item.isInventaire() && 0.1 < item.system.encombrement && item.system.encombrement <= 0.5 }, { group: "enc", code: "moyen", label: "Moyen (0.5 à 1.5)", check: (item, milieux) => item.isInventaire() && 0.5 < item.system.encombrement && item.system.encombrement <= 1.5 }, { group: "enc", code: "lourd", label: "Lourd (1.5 à 3)", check: (item, milieux) => item.isInventaire() && 1.5 < item.system.encombrement && item.system.encombrement <= 3 }, { group: "enc", code: "massif", label: "Massif (3 à 10)", check: (item, milieux) => item.isInventaire() && 3 < item.system.encombrement && item.system.encombrement <= 10 }, { group: "enc", code: "anemort", label: "Un âne mort (plus de 10)", check: (item, milieux) => item.isInventaire() && 10 < item.system.encombrement }, { group: "prix", code: "gratuit", label: "Gratuit", check: (item, milieux) => item.isInventaire() && item.system.cout == 0 }, { group: "prix", code: "deniers", label: "Deniers (étain)", check: (item, milieux) => item.isInventaire() && 0 < item.system.cout && item.system.cout < 0.1 }, { group: "prix", code: "bronze", label: "Sous (bronze)", check: (item, milieux) => item.isInventaire() && 0.1 <= item.system.cout && item.system.cout < 1 }, { group: "prix", code: "sols", label: "Sols (argent)", check: (item, milieux) => item.isInventaire() && 1 <= item.system.cout && item.system.cout < 10 }, { group: "prix", code: "dragons", label: "Dragons (or)", check: (item, milieux) => item.isInventaire() && 10 <= item.system.cout }, ] function $filterMilieux(milieux) { return milieux.map(m => { return { code: m, label: m, check: (item, milieux) => item.isPresentDansMilieux(m) } }) } function $filterRarete() { return RdDRaretes.raretes() .filter(it => it.frequence > 0) .map(r => { return { group: 'rarete', code: r.code, label: r.label, check: (item, milieux) => item.getRaretes(milieux).map(it => it.code).includes(r.code) } }); } function $filterTypes() { return RdDItem.getItemTypesInventaire().map(type => { return { group: 'type', code: type, label: Misc.typeName('Item', type), check: (item, milieux) => item.type == type }; }); } function $getAllFilters() { return FILTERS .concat($filterTypes()) .concat($filterRarete()); } function $addFilterToGroup(groups, filter) { if (filter.group && filter.code && filter.label) { let fg = groups.find(g => g.group == filter.group); if (fg == undefined) { groups.push({ group: filter.group, label: filter.group, filters: [filter] }) } else if (fg.filters == undefined) { fg.filters = [filter]; } else { fg.filters.push(filter); } } else { console.warn("Filtre incorrect, pas de groupe/code/label", filter); } } function $loadFilters(parameters) { $getAllFilters(parameters.milieux).forEach(f => $addFilterToGroup(parameters.filterGroups, f)); } export class FenetreRechercheTirage extends Application { static get defaultOptions() { return mergeObject(super.defaultOptions, { template: "systems/foundryvtt-reve-de-dragon/templates/tirage/fenetre-recherche-tirage.hbs", title: `Recherches et tirages`, width: 600, height: 600, popOut: true, dragDrop: [{ dragSelector: "a.content-link" }], resizable: true }); } static async create() { const milieux = await game.system.rdd.environnement.milieux(); const parameters = { milieux: milieux, filterMilieux: $filterMilieux(milieux), filterGroups: duplicate(FILTER_GROUPS).filter(it => it.group), } const options = {} $loadFilters(parameters); new FenetreRechercheTirage(parameters, options).render(true); } constructor(parameters, options) { super(options); this.parameters = parameters; } async getData() { return mergeObject(await super.getData(), this.parameters) } _canDragStart() { return true; } _onDragStart(event) { } _getHeaderButtons() { let buttons = super._getHeaderButtons(); if (game.user.isGM) { buttons.unshift({ class: "configurer", label: "Configurer", icon: "fas fa-cogs", onclick: ev => this.configurer() }); } return buttons } activateListeners(html) { super.activateListeners(html); this.html = html; this.showFilterGroup(this.html, false); this.html.find("a.section-filters-toggle").click(event => { const groupDiv = this.html.find(event.currentTarget)?.parents('div.section-filters-root').first(); const visible = groupDiv.find('div.section-filters-content').first().is(":visible"); this.showFilterGroup(groupDiv, !visible) }); this.html.find("input:is(.activate-filter-group,.activate-filter-milieu)").change(event => this.changeListeFiltresActifs()) this.html.find("a.supprimer-filtres").click(async event => this.supprimerFiltres()) this.html.find("a.recherche-filtres").click(async event => await this.recherche()) this.html.find("a.tirage-filtres").click(async event => { const table = await this.buildTable(); const row = await CompendiumTableHelpers.getRandom(table, 'Item') await CompendiumTableHelpers.tableRowToChatMessage(row, 'Item'); }) // this.html.find('.recherche') // .each((index, field) => { // if (this.options.recherche) { // field.focus(); // field.setSelectionRange(this.options.recherche.start, this.options.recherche.end); // } // }) // .keyup(async event => { // const nouvelleRecherche = this._optionRecherche(event.currentTarget); // if (this.options.recherche?.text != nouvelleRecherche?.text) { // this.options.recherche = nouvelleRecherche; // if (this.timerRecherche) { // clearTimeout(this.timerRecherche); // } // this.timerRecherche = setTimeout(() => { // this.timerRecherche = undefined; // this.render(true); // }, 500); // } // }) // .change(async event => // this.options.recherche = this._optionRecherche(event.currentTarget) // ); } showFilterGroup(groupDiv, show) { if (groupDiv) { HtmlUtility.showControlWhen(groupDiv.find('div.section-filters-content'), show); HtmlUtility.showControlWhen(groupDiv.find('i.section-filters-hide'), show); HtmlUtility.showControlWhen(groupDiv.find('i.section-filters-show'), !show); } } supprimerFiltres() { this.html.find('input:is(.activate-filter-group,.activate-filter-milieu)').prop("checked", false); this.html.find('div.liste-resultats-recherche').html(''); this.html.find('.section-filters-text input.recherche').val(''); } async recherche() { const table = await this.buildTable(); const htmlResultats = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/tirage/liste-resultats-recherche.hbs`, { resultats: table }); this.html.find('div.liste-resultats-recherche').html(htmlResultats); this._dragDrop.forEach(dragDropHandler => dragDropHandler.bind(this.element[0])) } async buildTable() { const milieux = this.getSelectedMilieux(); const filterItemMilieux = this.buildCheckedGroupFilter(milieux); const filter = it => filterItemMilieux(it, milieux); const itemFrequence = it => it.getFrequence(milieux); return await game.system.rdd.environnement.buildTable(itemFrequence, filter) } buildMilieuxFilter(milieux) { if (milieux) { return this.buildOrFilter(this.parameters.filterMilieux.filter(it => milieux.includes(it.code)).map(f => f.check)); } return (it, mi) => true; } buildFilterRechercheName() { const recherche = this.html.find('.section-filters-text input.recherche').val(); if (recherche) { return (it, mi) => Grammar.includesLowerCaseNoAccent(it.name, recherche); } return (it, mi) => true; } buildCheckedGroupFilter(milieux) { const filtersList = this.getGroupCheckedFilters() .map(gf => this.buildOrFilter(gf.filters.map(f => f.check))); filtersList.push(this.buildMilieuxFilter(milieux)); filtersList.push(this.buildFilterRechercheName()); return this.buildAndFilter(filtersList) } buildAndFilter(filters) { return filters.reduce((f1, f2) => { return (it, mi) => f1(it, mi) && f2(it, mi); }); } buildOrFilter(filters) { return filters.reduce((f1, f2) => { return (it, mi) => f1(it, mi) || f2(it, mi); }); } changeListeFiltresActifs() { const milieux = this.getSelectedMilieux(); const summariesList = this.getGroupCheckedFilters() .map(gf => { return gf.group.label + ': ' + gf.filters .map(f => f.label) .reduce(Misc.joining(', ')) }); if (milieux) { summariesList.push('Milieux: ' + this.parameters.filterMilieux.filter(f => milieux.includes(f.code)).map(f => f.label).reduce(Misc.joining(', '))) } const fullText = summariesList.length == 0 ? "" : summariesList.reduce(Misc.joining(' - ')); this.html.find('span.liste-filtres-actifs').text(fullText); } getGroupCheckedFilters() { const checkedGroupFilters = jQuery.map(this.html.find('input.activate-filter-group:checked'), it => this.html.find(it)) .map(element => { return { group: element.data('group'), code: element.data('code') }; }).filter(it => it.group); const entries = Object.entries(Misc.classify(checkedGroupFilters, it => it.group)); return entries.map(([key, list]) => { const group = this.parameters.filterGroups.find(g => g.group == key); const filters = list.map(it => group.filters.find(f => it.code == f.code)); return { group, filters }; }); } getSelectedMilieux() { const milieux = jQuery.map(this.html.find('input.activate-filter-milieu:checked'), it => { return this.html.find(it).data('code'); }); return milieux.length == 0 ? undefined : milieux } async configurer() { FenetreRechercheConfiguration.create(); } } class FenetreRechercheConfiguration extends Dialog { static async create() { const configuration = { compendiums: game.packs.filter(it => it.metadata.type == 'Item').map(it => it.metadata) .map(it => mergeObject({ selected: game.system.rdd.environnement.compendiums.includes(it.id) }, it)) } const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/tirage/fenetre-recherche-configuration.hbs", configuration); new FenetreRechercheConfiguration(html).render(true); } constructor(html) { const options = { classes: ["fenetre-recherche-configuration"], width: 600, height: 'fit-content', 'max-height': 600, height: 'fit-content', 'z-index': 99999 }; const conf = { title: 'Configuration de la recherche', content: html, buttons: { "Sauvegarder": { label: "Sauvegarder", callback: async it => { await this.sauvegarder(); } } } }; super(conf, options) } activateListeners(html) { this.html = html; super.activateListeners(html); this.html.find("button.configuration-save").click(event => this.sauvegarder()) } async sauvegarder() { const compendiumIds = jQuery.map(this.html.find("input.select-compendium:checked"), it => { return this.html.find(it).data('id'); }); await game.system.rdd.environnement.saveCompendiums(compendiumIds); this.close(); } }