diff --git a/module/environnement.js b/module/environnement.js index 09a243b2..b7713843 100644 --- a/module/environnement.js +++ b/module/environnement.js @@ -2,13 +2,7 @@ import { SYSTEM_RDD } from "./constants.js"; import { Grammar } from "./grammar.js"; import { Misc } from "./misc.js"; import { CompendiumTableHelpers, CompendiumTable } from "./settings/system-compendiums.js"; - -const RARETES = [ - { name: 'Commune', frequence: 54, min: 27, max: 108 }, - { name: 'Frequente', frequence: 18, min: 9, max: 36 }, - { name: 'Rare', frequence: 6, min: 3, max: 12 }, - { name: 'Rarissime', frequence: 2, min: 1, max: 4 }] -const DEFAULT_RARETE = 1; +import { RdDRaretes } from "./tirage/raretes.js"; const SETTINGS_LISTE_MILIEUX = "liste-milieux"; const MILIEUX = [ @@ -44,15 +38,6 @@ export class Environnement { this.table = new CompendiumTable('faune-flore-mineraux', 'Item', ITEM_ENVIRONNEMENT_TYPES) } - static getRarete(name = undefined) { - return RARETES.find(it => it.name == name) ?? RARETES[DEFAULT_RARETE]; - } - - static getFrequenceRarete(rarete, field = undefined) { - const selected = this.getRarete(rarete); - return selected[field]; - } - async milieux() { return Object.values(await this.mapMilieux()); } @@ -106,26 +91,20 @@ export class Environnement { return await CompendiumTableHelpers.getRandom(table, 'Item', ITEM_ENVIRONNEMENT_TYPES, undefined, typeName); } - async buildEnvironnementTable(milieux) { - const filterMilieux = item => item.system?.environnement.filter(env => milieux.includes(env.milieu)); - const itemRareteEnMilieu = item => { - const raretes = filterMilieux(item); - const frequenceMax = Math.max(raretes.map(env => env.frequence)); - return raretes.find(env => env.frequence == frequenceMax); + async buildEnvironnementTable(milieux, filter) { + if (!milieux){ + milieux = await this.milieux() } - const itemFrequenceEnMilieu = item => itemRareteEnMilieu(item)?.frequence ?? 0; - const isPresentEnMilieu = item => itemFrequenceEnMilieu(item) > 0; - return await this.table.buildTable(itemFrequenceEnMilieu, isPresentEnMilieu); + const frequence = item => item.getRarete(milieux)?.frequence ?? 0; + return await this.table.buildTable(frequence, it => frequence(it) > 0 && filter(it)); } - async getElements(itemFrequence, filter) { return await this.table.getContent(itemFrequence, filter); } } export class EnvironmentSheetHelper { - static defaultOptions(defaultOptions) { return mergeObject(defaultOptions, { tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "informations" }] @@ -170,12 +149,9 @@ export class EnvironmentSheetHelper { static $changeRarete(sheet, event, updated) { const name = sheet.html.find(event.currentTarget).val(); - const rarete = Environnement.getRarete(name); - updated.rarete = rarete.name; + const rarete = RdDRaretes.getRarete(name); + updated.rarete = rarete.code; updated.frequence = rarete.frequence; - // updated.frequence = Math.min( - // Math.max(rarete.min, updated.frequence ?? rarete.frequence), - // rarete.max); } static async onAddMilieu(sheet, event) { @@ -190,8 +166,8 @@ export class EnvironmentSheetHelper { ui.notifications.warn(`${sheet.item.name} a déjà une rareté ${exists.rarete} en ${milieu} (fréquence: ${exists.frequence})`); return } - const rarete = Environnement.getRarete(); - const newList = [...list, { milieu, rarete: rarete.name, frequence: rarete.frequence }].sort(Misc.ascending(it => it.milieu)) + const rarete = RdDRaretes.getRarete(); + const newList = [...list, { milieu, rarete: rarete.code, frequence: rarete.frequence }].sort(Misc.ascending(it => it.milieu)) await sheet.item.update({ 'system.environnement': newList }) } diff --git a/module/item.js b/module/item.js index 729e9385..51cd0b4c 100644 --- a/module/item.js +++ b/module/item.js @@ -5,6 +5,7 @@ import { RdDHerbes } from "./rdd-herbes.js"; import { RdDTimestamp } from "./rdd-timestamp.js"; import { RdDUtility } from "./rdd-utility.js"; import { SystemCompendiums } from "./settings/system-compendiums.js"; +import { RdDRaretes } from "./tirage/raretes.js"; const typesInventaireMateriel = [ "arme", @@ -32,6 +33,7 @@ const typesObjetsConnaissance = ["meditation", "recettealchimique", "sort"] const typesObjetsEffet = ["possession", "poison", "maladie"] const typesObjetsCompetence = ["competence", "competencecreature"] const typesObjetsTemporels = ["poison", "maladie", "queue", "ombre", "souffle", "signedraconique", "rencontre"] +const typesEnvironnement = ['herbe', 'faune', 'ingredient']; const encBrin = 0.00005; // un brin = 1 décigramme = 1/10g = 1/10000kg = 1/20000 enc const encPepin = 0.0007; /* un pépin de gemme = 1/10 cm3 = 1/1000 l = 3.5/1000 kg = 7/2000 kg = 7/1000 enc densité 3.5 (~2.3 à 4, parfois plus) -- https://www.juwelo.fr/guide-des-pierres/faits-et-chiffres/ @@ -107,6 +109,12 @@ export class RdDItem extends Item { static getItemTypesInventaire(mode = 'materiel') { return typesInventaire[mode ?? 'materiel'] } + static getItemTypesDraconiques() { + return typesObjetsDraconiques; + } + static getItemTypesEnvironnement() { + return typesEnvironnement; + } static getTypesOeuvres() { return typesObjetsOeuvres @@ -159,13 +167,46 @@ export class RdDItem extends Item { isCompetence() { return typesObjetsCompetence.includes(this.type) } isTemporel() { return typesObjetsTemporels.includes(this.type) } isOeuvre() { return typesObjetsOeuvres.includes(this.type) } - isDraconique() { return typesObjetsDraconiques.includes(this.type) } + isDraconique() { return RdDItem.getItemTypesDraconiques().includes(this.type) } isEffet() { return typesObjetsEffet.includes(this.type) } isConnaissance() { return typesObjetsConnaissance.includes(this.type) } isInventaire(mode = 'materiel') { return RdDItem.getItemTypesInventaire(mode).includes(this.type); } isAlcool() { return this.isNourritureBoisson() && this.system.boisson && this.system.alcoolise; } isHerbeAPotion() { return this.type == 'herbe' && (this.system.categorie == 'Soin' || this.system.categorie == 'Repos'); } + isEnvironnement() { return RdDItem.getItemTypesEnvironnement().includes(this.type) } + + isPresentDansMilieux(milieux) { + return this.getEnvironnements(milieux).length > 0 + } + getEnvironnements(milieux = undefined) { + return this.isEnvironnement() + ? this.system?.environnement.filter(env => !milieux || milieux.includes(env.milieu)) + : [] + } + getEnvRarete(milieux = undefined) { + if (this.isEnvironnement()) { + const list = this.getEnvironnements(milieux); + const frequenceMax = Math.max(...list.map(env => env.frequence)); + return list.find(env => env.frequence == frequenceMax); + } + return {} + } + + getRarete(milieux = undefined) { + if (this.isEnvironnement()) { + const env = this.getEnvRarete(milieux); + return RdDRaretes.getRarete(env.rarete); + } + if (this.isInventaire()) { + return RdDRaretes.rareteEquipement(this) + } + return RdDRaretes.getRareteFrequente(); + } + getFrequence(milieux = undefined) { + const frequence = this.getRarete(milieux)?.frequence; + return frequence == undefined ? 1 : frequence; + } getItemGroup() { if (this.isInventaire()) return "equipement"; diff --git a/module/migrations.js b/module/migrations.js index b8c0bbd5..45d9f84e 100644 --- a/module/migrations.js +++ b/module/migrations.js @@ -5,6 +5,7 @@ import { Grammar } from "./grammar.js"; import { Monnaie } from "./item-monnaie.js"; import { RdDItem } from "./item.js"; import { RdDTimestamp } from "./rdd-timestamp.js"; +import { RdDRaretes } from "./tirage/raretes.js"; class Migration { get code() { return "sample"; } @@ -288,10 +289,11 @@ class _10_3_0_FrequenceEnvironnement extends Migration { } _updatesFrequences(it) { + const rarete = RdDRaretes.getRarete(it.system.rarete); return { _id: it.id, 'system.rarete': undefined, - 'system.environnement': [{ milieu: it.system.milieu, rarete: it.system.rarete, frequence: Environnement.getFrequenceRarete(it.system.rarete, 'frequence') }] + 'system.environnement': [{ milieu: it.system.milieu, rarete: rarete.code, frequence: rarete.frequence }] } } } diff --git a/module/rdd-commands.js b/module/rdd-commands.js index c92ca693..2f48da54 100644 --- a/module/rdd-commands.js +++ b/module/rdd-commands.js @@ -14,6 +14,7 @@ import { RdDRollResolutionTable } from "./rdd-roll-resolution-table.js"; import { RdDRollTables } from "./rdd-rolltables.js"; import { RdDUtility } from "./rdd-utility.js"; import { CompendiumTableHelpers } from "./settings/system-compendiums.js"; +import { FenetreRechercheTirage } from "./tirage/fenetre-recherche-tirage.js"; import { TMRUtility } from "./tmr-utility.js"; const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/; @@ -23,6 +24,7 @@ export class RdDCommands { static init() { const rddCommands = new RdDCommands(); + game.system.rdd.commands = rddCommands; Hooks.on("chatMessage", (html, content, msg) => { if (content[0] == '/') { @@ -35,7 +37,6 @@ export class RdDCommands { return true; }); - game.system.rdd.commands = rddCommands; } constructor() { @@ -75,7 +76,8 @@ export class RdDCommands { this.registerCommand({ path: ["/tirer", "ideefixe"], func: (content, msg, params) => RdDRollTables.getIdeeFixe('chat'), descr: "Tire une Idée fixe" }); this.registerCommand({ path: ["/tirer", "desir"], func: (content, msg, params) => RdDRollTables.getDesirLancinant('chat'), descr: "Tire un Désir Lancinant" }); this.registerCommand({ path: ["/tirer", "rencontre"], func: (content, msg, params) => this.getRencontreTMR(params), descr: `Détermine une rencontre dans les TMR (synonyme de "/tmrr")` }); - this.registerCommand({ path: ["/tirer", "milieu"], func: (content, msg, params) => this.tableMilieu(msg, params, 'chat'), descr: "Effectue un tirage dans la table desressource naturelles pour un milieu donné" }); + this.registerCommand({ path: ["/tirer", "milieu"], func: (content, msg, params) => this.tableMilieu(msg, params, 'chat'), descr: "Effectue un tirage dans la table des ressource naturelles pour un milieu donné" }); + this.registerCommand({ path: ["/tirage"], func: (content, msg, params) => this.tirage(), descr: "Ouvre la fenêtre de recherche et tirage" }); this.registerCommand({ path: ["/meteo"], func: (content, msg, params) => this.getMeteo(msg, params), descr: "Propose une météo marine" }); this.registerCommand({ path: ["/nom"], func: (content, msg, params) => RdDNameGen.getName(msg, params), descr: "Génère un nom aléatoire" }); @@ -254,10 +256,7 @@ export class RdDCommands { } /* -------------------------------------------- */ - async help(msg) { - this.help(msg, undefined); - } - async help(msg, table) { + async help(msg, table = undefined) { let commands = [] this._buildSubTableHelp(commands, table ?? this.commandsTable); @@ -511,5 +510,8 @@ export class RdDCommands { return await RdDMeteo.getMeteo(); } + async tirage() { + new FenetreRechercheTirage({}).render(true); + } } diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 8fa4c4a5..97ae50fd 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -16,6 +16,7 @@ import { Environnement } from "./environnement.js"; import { RdDItemCompetence } from "./item-competence.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDTimestamp } from "./rdd-timestamp.js"; +import { RdDRaretes } from "./tirage/raretes.js"; /* -------------------------------------------- */ // This table starts at 0 -> niveau -10 @@ -202,6 +203,7 @@ export class RdDUtility { 'systems/foundryvtt-reve-de-dragon/templates/enum-periode.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-tmr-effet.html', // Partials + 'systems/foundryvtt-reve-de-dragon/templates/tirage/liste-resultats.hbs', 'systems/foundryvtt-reve-de-dragon/templates/common/timestamp.hbs', 'systems/foundryvtt-reve-de-dragon/templates/common/periodicite.hbs', 'systems/foundryvtt-reve-de-dragon/templates/common/enum-duree.hbs', @@ -298,7 +300,7 @@ export class RdDUtility { Handlebars.registerHelper('linkCompendium', (pack, id, name) => RdDUtility.linkCompendium(pack, id, name)); Handlebars.registerHelper('uniteQuantite', (itemId, actorId) => RdDUtility.getItem(itemId, actorId)?.getUniteQuantite()); Handlebars.registerHelper('isFieldInventaireModifiable', (type, field) => RdDItem.isFieldInventaireModifiable(type, field)); - Handlebars.registerHelper('getFrequenceRarete', (rarete, field) => Environnement.getFrequenceRarete(rarete, field)); + Handlebars.registerHelper('rarete-getChamp', (rarete, field) => RdDRaretes.getChamp(rarete, field)); return loadTemplates(templatePaths); } diff --git a/module/settings/system-compendiums.js b/module/settings/system-compendiums.js index b3148fc5..2128e8bd 100644 --- a/module/settings/system-compendiums.js +++ b/module/settings/system-compendiums.js @@ -177,7 +177,7 @@ export class SystemCompendiums extends FormApplication { */ export class CompendiumTable { - constructor(compendium, type, subTypes, sorting = undefined) { + constructor(compendium, type, subTypes = undefined, sorting = undefined) { this.compendium = compendium; this.type = type; this.subTypes = subTypes; @@ -187,13 +187,13 @@ export class CompendiumTable { async getContent(itemFrequence = it => it.system.frequence, filter = it => true) { return await SystemCompendiums.getContent(this.compendium, this.type, - it => this.subTypes.includes(it.type) && filter(it), + it => (!this.subTypes || this.subTypes.includes(it.type)) && filter(it), itemFrequence, this.sorting); } async buildTable(itemFrequence = it => it.system.frequence, filter = it => true) { - const elements = await this.getContent(filter, itemFrequence); + const elements = await this.getContent(itemFrequence, filter); return CompendiumTableHelpers.buildTable(elements, itemFrequence); } @@ -225,9 +225,23 @@ export class CompendiumTableHelpers { }); } - static async getRandom(table, type, subTypes, forcedRoll = undefined, localisation = undefined) { + static concatTables(...tables) { + const rows = tables.reduce((a, b) => a.concat(b)); + let max = 0; + const total = rows.map(it => it.frequence).reduce(Misc.sum(), 0); + return rows.map(row => { + const frequence = row.frequence; + row.min = max + 1; + row.max = max + frequence; + row.total = total + max += frequence; + return row; + }) + } + static async getRandom(table, type, subTypes = ['objet'], forcedRoll = undefined, localisation = undefined) { if (table.length == 0) { - ui.notifications.warn(`Aucun ${Misc.typeName(type, subTypes[0])} trouvé dans ${localisation ?? ' les compendiums'}`); + const typeName = Misc.typeName(type, subTypes[0]); + ui.notifications.warn(`Aucun ${typeName} trouvé dans ${localisation ?? ' les compendiums'}`); return undefined; } return await CompendiumTableHelpers.selectRow(table, forcedRoll); @@ -260,7 +274,7 @@ export class CompendiumTableHelpers { roll: row.roll, document: row.document, percentages, - typeName: Misc.typeName(type, row.document.type), + typeName: Misc.typeName(type, row.document?.type ?? 'objet'), isGM: game.user.isGM, }); const messageData = { diff --git a/module/tirage/fenetre-recherche-tirage.js b/module/tirage/fenetre-recherche-tirage.js new file mode 100644 index 00000000..37b06735 --- /dev/null +++ b/module/tirage/fenetre-recherche-tirage.js @@ -0,0 +1,217 @@ +import { RdDItem } from '../item.js'; +import { HtmlUtility } from '../html-utility.js'; +import { Misc } from "../misc.js"; +import { CompendiumTable, CompendiumTableHelpers, SystemCompendiums } from '../settings/system-compendiums.js'; +import { RdDRaretes } from './raretes.js'; + +const FILTER_GROUPS = [ + { group: 'type', label: "Type d'objet" }, + { group: 'comestible', label: 'Alimentaire' }, + { group: 'categorie', label: 'Utilisation' }, + { group: 'milieu', label: 'Milieu' }, + { group: 'rarete', label: 'Rarete' }, + { group: 'qualite', label: 'Qualité' }, + { group: 'enc', label: 'Encombrement' }, + { group: 'prix', label: 'Prix' }, +] + +const FILTERS = [ + { group: 'comestible', code: 'pret', label: 'Comestible', check: item => item.isComestible() == 'pret' }, + { group: 'comestible', code: 'alcool', label: 'Alcool', check: item => item.isAlcool() }, + { group: 'comestible', code: 'boisson', label: 'Boisson', check: item => item.isNourritureBoisson() && item.system.boisson }, + { group: 'comestible', code: 'brut', label: 'A préparer', check: item => item.isComestible() == 'brut' }, + { group: 'comestible', code: 'poison', label: 'Toxique', check: item => item.isComestible() == 'poison' }, + { group: 'comestible', code: 'non', label: 'Immangeable', check: item => !item.isComestible() || item.isComestible() == '' }, + + { group: 'categorie', code: 'alchimie', label: 'Alchimique', check: item => item.isEnvironnement() && item.system.categorie == 'Alchimie' }, + { group: 'categorie', code: 'cuisine', label: 'Cuisine', check: item => item.isEnvironnement() && item.system.categorie == 'Cuisine' }, + { group: 'categorie', code: 'repos', label: 'Repos', check: item => item.isEnvironnement() && item.system.categorie == 'Repos' }, + { group: 'categorie', code: 'soins', label: 'Soins', check: item => item.isEnvironnement() && item.system.categorie == 'Soin' }, + { group: 'categorie', code: 'autres', label: 'Autres', check: item => !item.isEnvironnement() || ['', 'Autre'].includes(item.system.categorie) }, + + { group: "qualite", code: "mauvaise", label: "Mauvaise (négative)", check: item => item.isInventaire() && item.system.qualite < 0 }, + { group: "qualite", code: "quelconque", label: "Quelconque (0)", check: item => item.isInventaire() && item.system.qualite == 0 }, + { group: "qualite", code: "correcte", label: "Correcte (1-3)", check: item => item.isInventaire() && 1 <= item.system.qualite && item.system.qualite <= 3 }, + { group: "qualite", code: "bonne", label: "Bonne (4-6)", check: item => item.isInventaire() && 4 <= item.system.qualite && item.system.qualite <= 6 }, + { group: "qualite", code: "excellente", label: "Excellente (7-9)", check: item => item.isInventaire() && 7 <= item.system.qualite && item.system.qualite <= 9 }, + { group: "qualite", code: "mythique", label: "Mythique (10+)", check: item => item.isInventaire() && 10 <= item.system.qualite }, + + { group: "enc", code: "negligeable", label: "Négligeable (jusqu'à 0.1)", check: item => item.isInventaire() && item.system.encombrement <= 0.1 }, + { group: "enc", code: "leger", label: "Léger (0.1 à 0.5)", check: item => item.isInventaire() && 0.1 < item.system.encombrement && item.system.encombrement <= 0.5 }, + { group: "enc", code: "moyen", label: "Moyen (0.5 à 1.5)", check: item => item.isInventaire() && 0.5 < item.system.encombrement && item.system.encombrement <= 1.5 }, + { group: "enc", code: "lourd", label: "Lourd (1.5 à 3)", check: item => item.isInventaire() && 1.5 < item.system.encombrement && item.system.encombrement <= 3 }, + { group: "enc", code: "massif", label: "Massif (3 à 10)", check: item => item.isInventaire() && 3 < item.system.encombrement && item.system.encombrement <= 10 }, + { group: "enc", code: "anemort", label: "Un âne mort (plus de 10)", check: item => item.isInventaire() && 10 < item.system.encombrement }, + + { group: "prix", code: "gratuit", label: "Gratuit", check: item => item.isInventaire() && item.system.cout == 0 }, + { group: "prix", code: "deniers", label: "Deniers (étain) 1-9", check: item => item.isInventaire() && 0 < item.system.cout && item.system.cout < 0.1 }, + { group: "prix", code: "bronze", label: "Bronzes 1-9", check: item => item.isInventaire() && 0.1 <= item.system.cout && item.system.cout < 1 }, + { group: "prix", code: "sols", label: "Sols (argent) 1-9", check: item => item.isInventaire() && 1 <= item.system.cout && item.system.cout < 10 }, + { group: "prix", code: "dragons", label: "Dragons (or) 1+ ", check: item => item.isInventaire() && 10 <= item.system.cout }, +] + +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, + resizable: true + }); + } + + static async $filterMilieux() { + const milieux = await game.system.rdd.environnement.milieux(); + return milieux.map(m => { return { group: 'milieu', code: m, label: m, check: item => item.isPresentDansMilieux(m) } }) + } + + static $filterRarete() { + return RdDRaretes.raretes() + .map(r => { return { group: 'rarete', code: r.code, label: r.label, check: item => item.getRarete()?.code == r.code }; }); + } + + static $filterTypes() { + return [ + { group: 'type', code: 'inventaire', label: 'Inventaire', check: item => item.isInventaire() && !item.isEnvironnement() }, + ] + .concat(['arme', 'armure'].map(it => FenetreRechercheTirage.$typeToFilter(it))) + .concat([{ group: 'type', code: 'environement', label: 'Faune, Flore, Ingrédients', check: item => item.isEnvironnement() }]) + .concat(RdDItem.getItemTypesEnvironnement().map(it => FenetreRechercheTirage.$typeToFilter(it))) + } + static $typeToFilter(type) { return { group: 'type', code: type, label: Misc.typeName('Item', type), check: item => item.type == type }; } + + static async create(tirage = {}) { + new FenetreRechercheTirage(tirage).render(true); + } + + constructor(tirage) { + super(); + this.tirage = tirage; + this.compendiums = [ + SystemCompendiums.getCompendium('faune-flore-mineraux'), + SystemCompendiums.getCompendium('equipement') + ] + } + + async getData() { + const filterGroups = duplicate(FILTER_GROUPS); + FILTERS + .concat(FenetreRechercheTirage.$filterTypes()) + .concat(await FenetreRechercheTirage.$filterMilieux()) + .concat(FenetreRechercheTirage.$filterRarete()) + .forEach(f => addFilterToGroup(filterGroups, f)) + mergeObject(this.tirage, + { + filterGroups: filterGroups.filter(it => it.group) + }) + + let formData = super.getData(); + mergeObject(formData, this.tirage) + return formData; + + function addFilterToGroup(filterGroups, filter) { + if (filter.group && filter.code && filter.label) { + let fg = filterGroups.find(g => g.group == filter.group); + if (fg == undefined) { + filterGroups.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); + } + } + } + + + activateListeners(html) { + super.activateListeners(html); + this.html = html; + + HtmlUtility.showControlWhen(this.html.find('div.group-filters'), false); + HtmlUtility.showControlWhen(this.html.find('i.filter-group-hide'), false); + HtmlUtility.showControlWhen(this.html.find('i.filter-group-show'), true); + + this.html.find("a.filter-group-toggle").click(event => { + const groupDiv = this.html.find(event.currentTarget)?.parents('div.filter-group').first(); + const visible = groupDiv.find('div.group-filters').first().is(":visible"); + this.showFilterGroup(groupDiv, !visible) + }); + + this.html.find("input.activate-filter").change(event => this.changeListeFiltresActifs()) + + this.html.find("a.supprimer-filtres").click(async event => this.html.find('input.activate-filter:checked').prop("checked", false)) + + this.html.find("a.recherche-filtres").click(async event => { + const table = await this.buildTable(); + this.html.find('div.liste-resultats').html(await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/tirage/liste-resultats.hbs`, { resultats: table })); + }) + + 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'); + }) + } + + async buildTable() { + const filter = this.getSelectedItemsFilter(); + const equipementCompendiumTable = new CompendiumTable('equipement', 'Item'); + const equipements = await equipementCompendiumTable.buildTable(it => it.getFrequence(), filter) + const environnements = await game.system.rdd.environnement.buildEnvironnementTable(undefined, filter); + return CompendiumTableHelpers.concatTables(environnements, equipements); + } + + getSelectedItemsFilter() { + const byGroup = this.getSelectedFiltersByGroup(); + const groupSummaries = Object.entries(byGroup).map(([key, list]) => { + const group = this.tirage.filterGroups.find(g => key == g.group); + const filters = list.map(it => it.code).map(code => group.filters.find(f => code == f.code)) + return filters + .map(f => f.check) + .reduce((a, b) => { return it => a(it) || b(it) });; + }); + if (groupSummaries.length == 0) { + return it => true; + } + return groupSummaries.reduce((a, b) => { return it => a(it) && b(it) }) + } + + showFilterGroup(groupDiv, show) { + if (groupDiv) { + HtmlUtility.showControlWhen(groupDiv.find('div.group-filters'), show); + HtmlUtility.showControlWhen(groupDiv.find('i.filter-group-hide'), show); + HtmlUtility.showControlWhen(groupDiv.find('i.filter-group-show'), !show); + } + } + + changeListeFiltresActifs() { + const byGroup = this.getSelectedFiltersByGroup(); + const groupSummaries = Object.entries(byGroup).map(([key, list]) => { + const group = this.tirage.filterGroups.find(g => key == g.group); + const filters = list.map(it => it.code).map(code => group.filters.find(f => code == f.code)) + return group.label + ': ' + filters + .map(f => f.label) + .reduce(Misc.joining(', '));; + }); + const fullText = groupSummaries.length == 0 ? "" : groupSummaries.reduce(Misc.joining(' - ')); + this.html.find('span.liste-filtres-actifs').text(fullText); + } + + getSelectedFiltersByGroup() { + const selectedFilters = jQuery.map(this.html.find('input.activate-filter:checked'), it => { + const element = this.html.find(it); + return { group: element.data('group'), code: element.data('code') }; + }); + const byGroup = Misc.classify(selectedFilters, it => it.group); + return byGroup; + } +} \ No newline at end of file diff --git a/module/tirage/raretes.js b/module/tirage/raretes.js new file mode 100644 index 00000000..dc6f4d28 --- /dev/null +++ b/module/tirage/raretes.js @@ -0,0 +1,45 @@ + +const RARETES = [ + { code: 'Commune', label: 'Commune', frequence: 54, min: 27, max: 108 }, + { code: 'Frequente', label: 'Fréquente', frequence: 18, min: 9, max: 36 }, + { code: 'Rare', label: 'Rare', frequence: 6, min: 3, max: 12 }, + { code: 'Rarissime', label: 'Rarissime', frequence: 2, min: 1, max: 4 }] +const DEFAULT_RARETE = 1; + +export class RdDRaretes { + + static getRarete(code = undefined) { + return RARETES.find(it => it.code == code) ?? RARETES[DEFAULT_RARETE]; + } + + static getChamp(rarete, field = undefined) { + const selected = this.getRarete(rarete); + return field ? selected[field] : selected[frequence]; + } + + static getRareteFrequente() { + return RARETES[DEFAULT_RARETE]; + } + + static raretes() { + return RARETES; + } + + static frequenceEquipement(item) { + return RdDRaretes.rareteEquipement(item).frequence + } + + static rareteEquipement(item) { + const qualite = item.system.qualite ?? 0; + if (qualite <= 0) { + return RARETES[0] + } + if (qualite <= 3) { + return RARETES[1] + } + if (qualite <= 6) { + return RARETES[2] + } + return RARETES[3] + } +} \ No newline at end of file diff --git a/packs/macros.db b/packs/macros.db index 7427c4fd..1256c709 100644 --- a/packs/macros.db +++ b/packs/macros.db @@ -7,5 +7,6 @@ {"name":"Appel à la chance","type":"script","scope":"global","author":"Hp9ImM4o9YRTSdfu","img":"icons/commodities/flowers/clover.webp","command":"const selected = game.system.rdd.RdDUtility.getSelectedActor();\nif (selected) {\n selected.rollAppelChance();\n}\nelse {\n ui.notifications.info('Pas de personnage sélectionné');\n}","ownership":{"default":0,"Hp9ImM4o9YRTSdfu":3},"flags":{"core":{"sourceId":"Macro.XHNbjnGKXaCiCadq"}},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.3.15","coreVersion":"10.291","createdTime":1671220038331,"modifiedTime":1671233849101,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"},"folder":null,"sort":0,"_id":"UzAWljmFq5sY702w"} {"name":"Encaissement","type":"script","scope":"global","author":"Hp9ImM4o9YRTSdfu","img":"icons/svg/bones.svg","command":"const selected = game.system.rdd.RdDUtility.getSelectedActor();\nif (selected) {\n selected.encaisser();\n}\nelse {\n ui.notifications.info('Pas de personnage sélectionné');\n}","ownership":{"default":0,"Hp9ImM4o9YRTSdfu":3},"flags":{"core":{"sourceId":"Macro.XHNbjnGKXaCiCadq"}},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.3.15","coreVersion":"10.291","createdTime":1671220038331,"modifiedTime":1671234017623,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"},"folder":null,"sort":0,"_id":"WD6T8AdRbX2Ylxqe"} {"name":"Jet quelconque","type":"script","scope":"global","author":"Hp9ImM4o9YRTSdfu","img":"icons/sundries/gaming/dice-runed-tan.webp","command":"const selected = game.system.rdd.RdDUtility.getSelectedActor();\nif (selected) {\n selected.roll();\n}\nelse {\n ui.notifications.info('Pas de personnage sélectionné');\n}","ownership":{"default":0,"Hp9ImM4o9YRTSdfu":3},"flags":{"core":{"sourceId":"Macro.XHNbjnGKXaCiCadq"}},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.3.15","coreVersion":"10.291","createdTime":1671220038331,"modifiedTime":1671233500655,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"},"folder":null,"sort":0,"_id":"bnJnbKDHpbqY8Pr9"} +{"name":"Recherche et tirage","type":"script","scope":"global","author":"Hp9ImM4o9YRTSdfu","img":"icons/tools/scribal/magnifying-glass.webp","command":"game.system.rdd.commands.tirage()","ownership":{"default":0,"Hp9ImM4o9YRTSdfu":3},"flags":{"core":{"sourceId":"Macro.ZFWPNdQBjQs9z0YW"}},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.5.4","coreVersion":"10.291","createdTime":1673472449426,"modifiedTime":1673655461651,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"},"folder":null,"sort":0,"_id":"iVZnxOxhCMpkvYh3"} {"name":"Jet d'éthylisme","type":"script","scope":"global","author":"Hp9ImM4o9YRTSdfu","img":"icons/consumables/drinks/alcohol-beer-stein-wooden-metal-brown.webp","command":"const selected = game.system.rdd.RdDUtility.getSelectedActor();\nif (selected) {\n selected.jetEthylisme();\n}\nelse {\n ui.notifications.info('Pas de personnage sélectionné');\n}","ownership":{"default":0,"Hp9ImM4o9YRTSdfu":3},"flags":{"core":{"sourceId":"Macro.XHNbjnGKXaCiCadq"}},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.3.15","coreVersion":"10.291","createdTime":1671220038331,"modifiedTime":1671233646086,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"},"folder":null,"sort":0,"_id":"mvub1dRHNFmWjRr7"} {"name":"Tirer le tarot","type":"chat","scope":"global","author":"Hp9ImM4o9YRTSdfu","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.webp","command":"/tirer tarot","ownership":{"default":0,"Hp9ImM4o9YRTSdfu":3},"flags":{"core":{"sourceId":"Macro.HBZSKR9OHCQbLcTC"}},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.3.15","coreVersion":"10.291","createdTime":1669469547231,"modifiedTime":1671237401618,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"},"folder":null,"sort":0,"_id":"vTfJTFYYiRu8X5LM"} diff --git a/styles/simple.css b/styles/simple.css index 4bf903bf..76d3c57c 100644 --- a/styles/simple.css +++ b/styles/simple.css @@ -469,6 +469,16 @@ input:is(.blessure-premiers_soins, .blessure-soins_complets) { .dice-img { border-width: 0; } +.in-text-img { + max-width: 1.2em; + max-height: 1.2em; + flex-grow: 0; + margin-right: 0.2rem; + vertical-align: bottom; + border: none; + padding: 0.1rem; +} + .button-img { vertical-align: baseline; max-width: 32px; @@ -677,10 +687,11 @@ div.dimmed .img-signe-heure { .competence-list .item-controls.hidden-controls { display: none !important; } -.item-controls i:is(.fas,.far) { +.item-controls i:is(.fas, .fa, .fa-solid) { + font-size: 0.8em; color: var(--color-controls); } -.item-controls i:is(.fas,.far):hover { +.item-controls i:is(.fas, .far, .fa-solid):hover { opacity: 0.7 ; } @@ -1929,3 +1940,37 @@ display: inline-flex; width: 80px; height: 68px; } + +div.vl { + border: 1px solid ; + border-color: hsla(0, 0%, 0%, 0.5); + height: inherit; + min-height: max-content; + margin-left: 0; + margin-right: 0; + width: 1px; + flex-grow: 0; +} +div.fenetre-recherche div.recherche { + display: flex; +} +div.fenetre-recherche div.recherche div.filtres { + width: fit-content; + min-width: 200px; + float: left; +} +div.fenetre-recherche div.titre-fenetre-recherche { + flex-basis: 0; + max-height: fit-content; +} +div.fenetre-recherche div.liste-resultats { + display: flex; + flex: auto; + flex-flow: row wrap; + flex-direction: row; + align-content: flex-start ; +} +div.fenetre-recherche div.liste-resultats div.resultat { + width: fit-content; + margin: 0.2rem 0.5rem; +} diff --git a/templates/common/compendium-link.hbs b/templates/common/compendium-link.hbs index 905a04b5..d8516b2f 100644 --- a/templates/common/compendium-link.hbs +++ b/templates/common/compendium-link.hbs @@ -5,10 +5,16 @@ data-pack="{{pack}}" {{#if doctype}}data-doctype="{{doctype}}"{{/if}} data-id="{{id}}" ->{{name}} +> {{else}} {{name}} +> {{/if}} +{{#if img}} +{{name}} +{{else}} + +{{/if}} +{{name}} diff --git a/templates/item/partial-environnement.html b/templates/item/partial-environnement.html index fe9e3846..49d8045b 100644 --- a/templates/item/partial-environnement.html +++ b/templates/item/partial-environnement.html @@ -29,8 +29,8 @@ {{>"systems/foundryvtt-reve-de-dragon/templates/enum-rarete.html"}} {{/select}} - {{rangePicker name="milieu-{{key}}-frequence" value=env.frequence min=(getFrequenceRarete env.rarete 'min') max=(getFrequenceRarete env.rarete 'max') step=1}} - + {{rangePicker name="milieu-{{key}}-frequence" value=env.frequence min=(rarete-getChamp env.rarete 'min') max=(rarete-getChamp env.rarete 'max') step=1}} + {{/each}} diff --git a/templates/tirage/fenetre-recherche-tirage.hbs b/templates/tirage/fenetre-recherche-tirage.hbs new file mode 100644 index 00000000..73f682e3 --- /dev/null +++ b/templates/tirage/fenetre-recherche-tirage.hbs @@ -0,0 +1,49 @@ +
+
+ Tout + Appliquer les filtres + Tirage aléatoire + +
+
+
+
+
+

Filtres

+
+ {{#each filterGroups as |group|}} +
+

{{group.label}} + + + + + +

+
+ {{#each group.filters as |filter|}} +
+ + +
+ {{/each}} +
+
+ {{/each}} +
+
+
+
+
+

Résultat de recherche

+
+
+ +
+
+
+ + {{!-- + --}} + \ No newline at end of file diff --git a/templates/tirage/liste-resultats.hbs b/templates/tirage/liste-resultats.hbs new file mode 100644 index 00000000..2f505251 --- /dev/null +++ b/templates/tirage/liste-resultats.hbs @@ -0,0 +1,9 @@ +{{#each resultats as |row|}} +
+ {{>'systems/foundryvtt-reve-de-dragon/templates/common/compendium-link.hbs' + pack=row.document.pack + id=row.document.id + name=row.document.name + img=row.document.img}} +
+{{/each}} \ No newline at end of file