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}}
+
+{{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 @@
+