diff --git a/module/environnement.js b/module/environnement.js
new file mode 100644
index 00000000..4d8499dd
--- /dev/null
+++ b/module/environnement.js
@@ -0,0 +1,222 @@
+import { SYSTEM_RDD } from "./constants.js";
+import { Grammar } from "./grammar.js";
+import { Misc } from "./misc.js";
+import { CompendiumTableHelpers, SystemCompendiums, 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 SETTINGS_LISTE_MILIEUX = "liste-milieux";
+const MILIEUX = [
+ "Collines",
+ "Déserts",
+ "Désolations",
+ "Forêts",
+ "Forêts Tropicales",
+ "Marais",
+ "Milieux Aquatiques",
+ "Milieux Maritimes",
+ "Montagnes",
+ "Plaines",
+ "Sous-Sols",
+]
+const ITEM_ENVIRONNEMENT_TYPES = [
+ 'herbe', 'ingredient'
+]
+const COMPENDIUMS_ENVIRONNEMENT = [
+ { type: 'Item', subType: 'herbe', compendium: 'botanique' },
+ { type: 'Item', subType: 'ingredient', compendium: 'botanique' },
+ { type: 'Item', subType: 'ingredient', compendium: 'equipement' },
+]
+
+export class Environnement {
+
+ static init() {
+ game.settings.register(SYSTEM_RDD, SETTINGS_LISTE_MILIEUX, {
+ name: "Liste des milieux proposés",
+ hint: "Liste des noms de milieux proposés, séparés par des virgules",
+ scope: "world",
+ config: true,
+ default: MILIEUX.reduce(Misc.joining(',')),
+ type: String
+ });
+ game.system.rdd.environnement = new Environnement();
+ }
+
+ constructor() {
+ this.table = new CompendiumTable('faune-flore-mineraux', 'Item', ITEM_ENVIRONNEMENT_TYPES)
+ }
+
+ static getRarete(name = undefined) {
+ return RARETES.find(it => it.name == name) ?? RARETES[0];
+ }
+
+ static getFrequenceRarete(rarete, field = undefined) {
+ const selected = this.getRarete(rarete);
+ return selected[field];
+ }
+
+ async milieux() {
+ const milieux = new Set(this.getMilieuxSettings());
+ const elements = await this.getElements(it => 1, it => ITEM_ENVIRONNEMENT_TYPES.includes(it.type));
+ elements.forEach(it => it.system.environnement.forEach(env => milieux.add(env.milieu)))
+ return [...milieux];
+ }
+
+ getMilieuxSettings() {
+ return game.settings.get(SYSTEM_RDD, SETTINGS_LISTE_MILIEUX).split(',');
+ }
+
+ async findEnvironnementsLike(search) {
+ return (await this.milieux()).filter(it => Grammar.includesLowerCaseNoAccent(it, search));
+ }
+
+ async searchToChatMessage(search) {
+ const table = await this.buildEnvironnementTable(search);
+ await CompendiumTableHelpers.tableToChatMessage(table, 'Item', 'herbe', 'Ressource naturelle');
+ return true
+ }
+
+ async getRandom(search) {
+ const table = await this.buildEnvironnementTable(search);
+ const row = await CompendiumTableHelpers.getRandom(table, 'Item', 'herbe', undefined, 'Ressource naturelle');
+ return row
+ }
+
+ async buildEnvironnementTable(search) {
+ const itemRareteEnMilieu = item => item.system?.environnement.find(env => Grammar.includesLowerCaseNoAccent(env.milieu, search));
+ const itemFrequenceEnMilieu = item => itemRareteEnMilieu(item)?.frequence ?? 0;
+ const isPresentEnMilieu = item => itemFrequenceEnMilieu(item) > 0;
+ let elements = await this.getElements(itemFrequenceEnMilieu, isPresentEnMilieu);
+ return CompendiumTableHelpers.buildTable(elements, itemFrequenceEnMilieu);
+ }
+
+
+ async getElements(itemFrequence, filter) {
+ let elements = [];
+ for (let c of COMPENDIUMS_ENVIRONNEMENT) {
+ const fromCompendium = await c.table.getContent(itemFrequence, filter);
+ elements = elements.concat(fromCompendium);
+ }
+ return elements;
+ }
+}
+
+export class EnvironmentSheetHelper {
+
+ static defaultOptions(defaultOptions, type) {
+ return mergeObject(defaultOptions, {
+ classes: ["rdd", "sheet", "item"],
+ template: `systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html`,
+ width: 500,
+ height: 600,
+ tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "informations" }]
+ });
+ }
+
+ /* -------------------------------------------- */
+ static getHeaderButtons(sheet, buttons) {
+ buttons.unshift({ class: "post", icon: "fas fa-comment", onclick: ev => sheet.item.postItem() });
+ return buttons;
+ }
+
+ static setPosition(sheet, superPosition) {
+ const position = superPosition;
+ const sheetHeader = sheet.element.find(".sheet-header");
+ const sheetBody = sheet.element.find(".sheet-body");
+ sheetBody.css("height", position.height - sheetHeader[0].clientHeight)
+ return position;
+ }
+
+ /* -------------------------------------------- */
+ static async getData(sheet) {
+ const formData = duplicate(sheet.item);
+ const milieux = await game.system.rdd.environnement.milieux();
+ const milieuxDisponibles = milieux.filter(it => !sheet.item.system.environnement.find(e => e.milieu == it));
+ mergeObject(formData, {
+ title: formData.name,
+ isGM: game.user.isGM,
+ owner: sheet.actor?.isOwner,
+ isOwned: sheet.actor ? true : false,
+ actorId: sheet.actor?.id,
+ editable: sheet.isEditable,
+ cssClass: sheet.isEditable ? "editable" : "locked",
+ milieux: milieuxDisponibles
+ });
+ return formData;
+ }
+
+ static activateListeners(sheet, html) {
+ if (!sheet.options.editable) return;
+ html.find("a.milieu-add").click(event => EnvironmentSheetHelper.onAddMilieu(sheet, event));
+ html.find("div.environnement-milieu a.milieu-delete").click(event => EnvironmentSheetHelper.onDeleteMilieu(sheet, event));
+ html.find("div.environnement-milieu select.environnement-rarete").change(event => EnvironmentSheetHelper.onChange(sheet, event,
+ (updated) => {
+ const name = $(event.currentTarget).val();
+ const rarete = Environnement.getRarete(name);
+ updated.rarete = rarete.name;
+ updated.frequence = Math.min(
+ Math.max(rarete.min, updated.frequence ?? rarete.frequence),
+ rarete.max);
+ }));
+ html.find("div.environnement-milieu input[name='environnement-frequence']").change(event => EnvironmentSheetHelper.onChange(sheet, event,
+ (updated) => {
+ updated.frequence = Number($(event.currentTarget).val())
+ }));
+ }
+
+ static async onAddMilieu(sheet, event) {
+ const milieu = $("input.input-selection-milieu").val();
+ if (!milieu) {
+ ui.notifications.warn(`Choisissez le milieu dans lequel se trouve le/la ${sheet.item.name}`);
+ return
+ }
+ const list = sheet.item.system.environnement;
+ const exists = list.find(it => it.milieu == milieu);
+ if (exists) {
+ 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))
+ await sheet.item.update({ 'system.environnement': newList })
+ }
+
+ static async onDeleteMilieu(sheet, event) {
+ const milieu = EnvironmentSheetHelper.$getEventMilieu(event);
+ if (milieu) {
+ const newList = sheet.item.system.environnement.filter(it => it.milieu != milieu)
+ .sort(Misc.ascending(it => it.milieu));
+ await sheet.item.update({ 'system.environnement': newList });
+ }
+ }
+
+ static async onChange(sheet, event, doMutation) {
+ const list = sheet.item.system.environnement;
+ const milieu = EnvironmentSheetHelper.$getEventMilieu(event);
+ const updated = list.find(it => it.milieu == milieu);
+ if (updated) {
+ doMutation(updated);
+ const newList = [...list.filter(it => it.milieu != milieu), updated]
+ .sort(Misc.ascending(it => it.milieu));
+ await sheet.item.update({ 'system.environnement': newList });
+ }
+ }
+
+ static $getEventMilieu(event) {
+ return $(event.currentTarget)?.parents("div.environnement-milieu").data("milieu");
+ }
+
+ static template(itemType) {
+ /* -------------------------------------------- */
+ return `systems/foundryvtt-reve-de-dragon/templates/item-${itemType}-sheet.html`;
+ }
+
+ static title(item) {
+ return Misc.typeName('Item', item.type) + ': ' + item.name;
+ }
+
+}
\ No newline at end of file
diff --git a/module/item-herbe-sheet.js b/module/item-herbe-sheet.js
new file mode 100644
index 00000000..2ba7d546
--- /dev/null
+++ b/module/item-herbe-sheet.js
@@ -0,0 +1,45 @@
+import { SYSTEM_RDD } from "./constants.js";
+import { EnvironmentSheetHelper as EnvironmentItemSheet } from "./environnement.js";
+import { Misc } from "./misc.js";
+
+const ITEM_TYPE = 'herbe';
+
+export class RdDHerbeItemSheet extends ItemSheet {
+
+ static register() {
+ Items.registerSheet(SYSTEM_RDD, RdDHerbeItemSheet, {
+ label: Misc.typeName('Item', ITEM_TYPE),
+ types: [ITEM_TYPE],
+ makeDefault: true
+ });
+ }
+
+ static get defaultOptions() {
+ return EnvironmentItemSheet.defaultOptions(super.defaultOptions, ITEM_TYPE);
+ }
+
+ _getHeaderButtons() {
+ return EnvironmentItemSheet.getHeaderButtons(this, super._getHeaderButtons());
+ }
+
+ setPosition(options = {}) {
+ return EnvironmentItemSheet.setPosition(this, super.setPosition(options));
+ }
+
+ async getData() {
+ return await EnvironmentItemSheet.getData(this);
+ }
+
+ activateListeners(html) {
+ super.activateListeners(html);
+ EnvironmentItemSheet.activateListeners(this, html);
+ }
+
+ get template() {
+ return EnvironmentItemSheet.template(this.item.type);
+ }
+
+ get title() {
+ return EnvironmentItemSheet.title(this.item);
+ }
+}
diff --git a/module/item-ingredient-sheet.js b/module/item-ingredient-sheet.js
new file mode 100644
index 00000000..b5b0d322
--- /dev/null
+++ b/module/item-ingredient-sheet.js
@@ -0,0 +1,44 @@
+import { SYSTEM_RDD } from "./constants.js";
+import { EnvironmentSheetHelper } from "./environnement.js";
+import { Misc } from "./misc.js";
+
+const ITEM_TYPE = 'ingredient';
+export class RdDIngredientItemSheet extends ItemSheet {
+
+ static register() {
+ Items.registerSheet(SYSTEM_RDD, RdDIngredientItemSheet, {
+ label: Misc.typeName('Item', ITEM_TYPE),
+ types: [ITEM_TYPE],
+ makeDefault: true
+ });
+ }
+
+ static get defaultOptions() {
+ return EnvironmentSheetHelper.defaultOptions(super.defaultOptions, ITEM_TYPE);
+ }
+
+ _getHeaderButtons() {
+ return EnvironmentSheetHelper.getHeaderButtons(this, super._getHeaderButtons());
+ }
+
+ setPosition(options = {}) {
+ return EnvironmentSheetHelper.setPosition(this, super.setPosition(options));
+ }
+
+ async getData() {
+ return await EnvironmentSheetHelper.getData(this);
+ }
+
+ activateListeners(html) {
+ super.activateListeners(html);
+ EnvironmentSheetHelper.activateListeners(this, html);
+ }
+
+ get template() {
+ return EnvironmentSheetHelper.template(this.item.type);
+ }
+
+ get title() {
+ return EnvironmentSheetHelper.title(this.item);
+ }
+}
diff --git a/module/migrations.js b/module/migrations.js
index ab644b77..a6bbba97 100644
--- a/module/migrations.js
+++ b/module/migrations.js
@@ -1,6 +1,6 @@
import { LOG_HEAD, SYSTEM_RDD } from "./constants.js";
+import { Environnement } from "./environnement.js";
import { Grammar } from "./grammar.js";
-import { Misc } from "./misc.js";
class Migration {
get code() { return "sample"; }
@@ -179,6 +179,7 @@ class _10_2_5_ArmesTirLancer extends Migration {
return Grammar.toLowerCaseNoAccent(it.system.competence);
}
}
+
class _10_2_10_DesirLancinant_IdeeFixe extends Migration {
get code() { return "desir-lancinat-idee-fixe"; }
get version() { return "10.2.10"; }
@@ -240,6 +241,24 @@ class _10_3_0_Inventaire extends Migration {
}
}
+class _10_3_0_FrequenceEnvironnement extends Migration {
+ get code() { return "migration-frequence-resources"; }
+ get version() { return "10.3.0"; }
+
+ async migrate() {
+ await this.applyItemsUpdates(items => items.filter(it => ['herbe', 'ingredient'].includes(it.type))
+ .map(it => this._updatesFrequences(it)));
+ }
+
+ _updatesFrequences(it) {
+ return {
+ _id: it.id,
+ 'system.rarete': undefined,
+ 'system.environnement': [{ milieu: it.system.milieu, rarete: it.system.rarete, frequence: Environnement.getFrequenceRarete(it.system.rarete, 'frequence') }]
+ }
+ }
+}
+
export class Migrations {
static getMigrations() {
return [
@@ -249,7 +268,8 @@ export class Migrations {
new _10_0_33_MigrationNomsDraconic(),
new _10_2_5_ArmesTirLancer(),
new _10_2_10_DesirLancinant_IdeeFixe(),
- new _10_3_0_Inventaire()
+ new _10_3_0_Inventaire(),
+ new _10_3_0_FrequenceEnvironnement()
];
}
@@ -264,11 +284,9 @@ export class Migrations {
}
migrate() {
- const currentVersion = game.settings.get(
- SYSTEM_RDD,
- "systemMigrationVersion"
- );
- if (isNewerVersion(game.system.version, currentVersion)) {
+ const currentVersion = game.settings.get(SYSTEM_RDD,"systemMigrationVersion");
+ //if (isNewerVersion(game.system.version, currentVersion)) {
+ if (true) { /* comment previous and uncomment here to test before upgrade */
const migrations = Migrations.getMigrations().filter(m => isNewerVersion(m.version, currentVersion));
if (migrations.length > 0) {
migrations.sort((a, b) =>
diff --git a/module/rdd-commands.js b/module/rdd-commands.js
index 5f0766da..d5f3f39e 100644
--- a/module/rdd-commands.js
+++ b/module/rdd-commands.js
@@ -13,6 +13,7 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
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 { TMRUtility } from "./tmr-utility.js";
const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/;
@@ -49,7 +50,9 @@ export class RdDCommands {
/table rencontre deso affiche la table des rencontres en Désolation
/table rencontre mauvaise affiche la table des mauvaises rencontres`
});
-
+ this.registerCommand({ path: ["/table", "milieu"], func: (content, msg, params) => this.tableMilieu(msg, params,'liste'), descr: "Affiche la table des trouvailles dans un milieu donné" });
+ this.registerCommand({ path: ["/tirer", "milieu"], func: (content, msg, params) => this.tableMilieu(msg, params, 'chat'), descr: "Affiche la table des trouvailles dans un milieu donné" });
+
this.registerCommand({ path: ["/tirer", "comp"], func: (content, msg, params) => RdDRollTables.getCompetence('chat'), descr: "Tire une compétence au hasard" });
this.registerCommand({ path: ["/tirer", "queue"], func: (content, msg, params) => RdDRollTables.getQueue('chat'), descr: "Tire une Queue de Dragon" });
this.registerCommand({ path: ["/tirer", "ombre"], func: (content, msg, params) => RdDRollTables.getOmbre('chat'), descr: "Tire une Ombre de Thanatos" });
@@ -363,6 +366,7 @@ export class RdDCommands {
}
return false;
}
+
async tableRencontres(msg, params) {
if (params && params.length > 0) {
const search = Misc.join(params, ' ');
@@ -370,11 +374,29 @@ export class RdDCommands {
if (solvedTerrain == undefined) {
return RdDCommands._chatAnswer(msg, 'Aucune TMR correspondant à ' + search);
}
- return game.system.rdd.rencontresTMR.chatTable(solvedTerrain);
+ return await game.system.rdd.rencontresTMR.chatTable(solvedTerrain);
}
return false;
}
+ async tableMilieu(msg, params, toChat) {
+ if (params && params.length > 0) {
+ const search = Misc.join(params, ' ');
+ const searches = game.system.rdd.environnement.findEnvironnementsLike(search);
+ if (searches.length == 0) {
+ return RdDCommands._chatAnswer(msg, 'Aucun milieu correspondant à ' + search);
+ }
+ if (toChat == 'liste') {
+ return await game.system.rdd.environnement.searchToChatMessage(search);
+ }
+ else {
+ const row = await game.system.rdd.environnement.getRandom(search);
+ await CompendiumTableHelpers.tableRowToChatMessage(row, 'Item');
+ return true;
+ }
+ }
+ return false;
+ }
/* -------------------------------------------- */
getCoutXpComp(msg, params) {
if (params && (params.length == 1 || params.length == 2)) {
diff --git a/module/rdd-main.js b/module/rdd-main.js
index d7bad8a6..50f49f90 100644
--- a/module/rdd-main.js
+++ b/module/rdd-main.js
@@ -39,6 +39,9 @@ import { DialogChronologie } from "./dialog-chronologie.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { RdDRencontreItemSheet } from "./item-rencontre-sheet.js";
import { TMRRencontres } from "./tmr-rencontres.js";
+import { RdDHerbeItemSheet } from "./item-herbe-sheet.js";
+import { Environnement } from "./environnement.js";
+import { RdDIngredientItemSheet } from "./item-ingredient-sheet.js";
/* -------------------------------------------- */
/* Foundry VTT Initialization */
@@ -194,11 +197,13 @@ Hooks.once("init", async function () {
types: ["rencontre"],
makeDefault: true
});
+ RdDHerbeItemSheet.register();
+ RdDIngredientItemSheet.register();
Items.registerSheet(SYSTEM_RDD, RdDItemSheet, {
types: [
"competence", "competencecreature",
"recettealchimique", "musique", "chant", "danse", "jeu", "recettecuisine", "oeuvre",
- "objet", "arme", "armure", "conteneur", "herbe", "ingredient", "livre", "potion", "munition",
+ "objet", "arme", "armure", "conteneur", "livre", "potion", "munition",
"monnaie", "nourritureboisson", "gemme",
"meditation", "queue", "ombre", "souffle", "tete", "casetmr", "sort", "sortreserve",
"nombreastral", "tache", "maladie", "poison", "possession",
@@ -224,6 +229,7 @@ Hooks.once("init", async function () {
RdDHotbar.initDropbar();
RdDPossession.init();
TMRRencontres.init();
+ Environnement.init();
});
/* -------------------------------------------- */
diff --git a/module/rdd-rolltables.js b/module/rdd-rolltables.js
index cf557a4c..0c8d50d2 100644
--- a/module/rdd-rolltables.js
+++ b/module/rdd-rolltables.js
@@ -1,5 +1,5 @@
import { Grammar } from "./grammar.js";
-import { SystemCompendiums } from "./settings/system-compendiums.js";
+import { CompendiumTable, CompendiumTableHelpers, SystemCompendiums } from "./settings/system-compendiums.js";
export class RdDRollTables {
@@ -37,7 +37,7 @@ export class RdDRollTables {
/* -------------------------------------------- */
static async getCompetence(toChat = false) {
if (toChat == 'liste') {
- return await SystemCompendiums.chatTableItems('competences', 'Item', 'competence', it => 1);
+ return await RdDRollTables.listOrRoll('competences', 'Item', 'competence', toChat, it => 1);
}
else {
return await RdDRollTables.drawItemFromRollTable("Détermination aléatoire de compétence", toChat);
@@ -55,13 +55,15 @@ export class RdDRollTables {
}
static async getDesirLancinant(toChat = false) {
- return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', 'queue', toChat, it => it.system.frequence,
- it => it.system.categorie == 'lancinant' );
+ return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', 'queue', toChat,
+ it => it.system.frequence,
+ it => it.system.categorie == 'lancinant');
}
static async getIdeeFixe(toChat = false) {
- return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', 'queue', toChat, it => it.system.frequence,
- it => it.system.categorie == 'ideefixe' );
+ return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', 'queue', toChat,
+ it => it.system.frequence,
+ it => it.system.categorie == 'ideefixe');
}
/* -------------------------------------------- */
@@ -86,10 +88,15 @@ export class RdDRollTables {
/* -------------------------------------------- */
static async listOrRoll(compendium, type, subType, toChat, itemFrequence = it => it.system.frequence, filter = it => true) {
+ const table = new CompendiumTable(compendium, type, subType);
if (toChat == 'liste') {
- return await SystemCompendiums.chatTableItems(compendium, type, subType, itemFrequence, filter);
+ return await table.toChatMessage(itemFrequence, filter);
}
- return await SystemCompendiums.getRandom(compendium, type, subType, toChat, itemFrequence, filter);
+ const row = await table.getRandom(itemFrequence, filter);
+ if (row) {
+ await CompendiumTableHelpers.tableRowToChatMessage(row, type);
+ }
+ return row;
}
/* -------------------------------------------- */
diff --git a/module/rdd-utility.js b/module/rdd-utility.js
index ba4cdf82..c747e221 100644
--- a/module/rdd-utility.js
+++ b/module/rdd-utility.js
@@ -15,6 +15,7 @@ import { RdDNameGen } from "./rdd-namegen.js";
import { RdDConfirm } from "./rdd-confirm.js";
import { RdDCalendrier } from "./rdd-calendrier.js";
import { RdDCarac } from "./rdd-carac.js";
+import { Environnement } from "./environnement.js";
/* -------------------------------------------- */
// This table starts at 0 -> niveau -10
@@ -169,7 +170,11 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/actor/liens-suivants.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/liens-vehicules.html',
//Items
+ 'systems/foundryvtt-reve-de-dragon/templates/scripts/autocomplete-script.hbs',
+ 'systems/foundryvtt-reve-de-dragon/templates/scripts/autocomplete.hbs',
'systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.html',
+ 'systems/foundryvtt-reve-de-dragon/templates/item/partial-environnement.html',
+ 'systems/foundryvtt-reve-de-dragon/templates/item/partial-tab-environnement.html',
'systems/foundryvtt-reve-de-dragon/templates/header-item.html',
'systems/foundryvtt-reve-de-dragon/templates/item-competence-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-competencecreature-sheet.html',
@@ -326,7 +331,8 @@ export class RdDUtility {
Handlebars.registerHelper('linkCompendium', (compendium, id, name) => `@Compendium[${compendium}.${id}]{${name}}`);
Handlebars.registerHelper('uniteQuantite', (type) => RdDItem.getUniteQuantite(type));
Handlebars.registerHelper('isEquipementFieldEditable', (type, field) => RdDItem.isEquipementFieldEditable(type, field));
-
+ Handlebars.registerHelper('getFrequenceRarete', (rarete, field) => Environnement.getFrequenceRarete(rarete, field));
+ Handlebars.registerHelper('either', (a, b) => a ?? b);
return loadTemplates(templatePaths);
}
diff --git a/module/settings/system-compendiums.js b/module/settings/system-compendiums.js
index b4d95bc4..d562e4bb 100644
--- a/module/settings/system-compendiums.js
+++ b/module/settings/system-compendiums.js
@@ -16,8 +16,13 @@ const CONFIGURABLE_COMPENDIUMS = {
'rencontres': { label: "Rencontres dans les TMR", type: "Item" },
'tetes-de-dragon-pour-haut-revants': { label: "Têtes de dragons (haut-rêvant)", type: "Item" },
'tetes-de-dragon-pour-tous-personnages': { label: "Têtes de dragons (tous)", type: "Item" },
+ 'botanique': { label: "Herbes & plantes", type: "Item" },
+ 'equipement': { label: "Equipements", type: "Item" },
}
+/**
+ * ======= Gestion des accès aux compendiums systèmes (ou surchargés) =======
+ */
export class SystemCompendiums extends FormApplication {
static init() {
Object.keys(CONFIGURABLE_COMPENDIUMS).forEach(compendium => {
@@ -50,7 +55,7 @@ export class SystemCompendiums extends FormApplication {
return game.packs.get(SystemCompendiums.getCompendium(compendium));
}
- static async getContent(compendium, docType) {
+ static async getPackContent(compendium, docType) {
const pack = SystemCompendiums.getPack(compendium);
if (pack.metadata.type == docType) {
return await pack.getDocuments();
@@ -83,35 +88,17 @@ export class SystemCompendiums extends FormApplication {
}
static async getItems(compendium, itemType = undefined) {
- const items = await SystemCompendiums.getContent(compendium, 'Item');
+ const items = await SystemCompendiums.getPackContent(compendium, 'Item');
return (itemType ? items.filter(it => it.type == itemType) : items);
}
- static async buildTable(compendium, itemFrequence, filter, type = 'Item', sorting = undefined) {
- let elements = await SystemCompendiums.getContent(compendium, type);
- elements = elements.filter(filter).filter(it => itemFrequence(it) > 0)
+ static async getContent(compendium, type, filter, itemFrequence, sorting) {
+ let elements = await SystemCompendiums.getPackContent(compendium, type);
+ elements = elements.filter(filter).filter(it => itemFrequence(it) > 0);
if (sorting) {
elements = elements.sort(sorting);
}
- let max = 0;
- const table = elements
- .map(it => {
- const frequence = itemFrequence(it)
- let row = { document: it, frequence: frequence, min: max + 1, max: max + frequence }
- max += frequence;
- return row;
- });
- table.forEach(it => it.total = max);
- return table;
- }
-
- static async getRandom(compendium, type, subType, toChat = true, itemFrequence = it => it.system.frequence, filter = it => true) {
- const table = new SystemCompendiumTable(compendium, type, subType);
- return await table.getRandom(toChat, itemFrequence, filter);
- }
- static async chatTableItems(compendium, type, subType, itemFrequence = it => it.system.frequence, filter = it => true) {
- const table = new SystemCompendiumTable(compendium, type, subType, itemFrequence);
- await table.chatTable(itemFrequence, filter);
+ return elements;
}
static async getDefaultItems(compendium) {
@@ -180,48 +167,69 @@ export class SystemCompendiums extends FormApplication {
}
}
-export class SystemCompendiumTable {
+/**
+ * ======= Gestion de jets dans une table correspondant à un compendium =======
+ */
+export class CompendiumTable {
constructor(compendium, type, subType, sorting = undefined) {
this.compendium = compendium;
this.type = type;
this.subType = subType;
- this.compendium = compendium;
- this.sourceCompendium = SystemCompendiums.getCompendium(compendium);
- this.sorting = sorting
+ this.sorting = sorting ?? Misc.ascending(it => it.name);
}
- typeName() {
- return Misc.typeName(this.type, this.subType);
- }
- applyType(filter) {
- return it => it.type == this.subType && filter(it);
+ async getContent(itemFrequence = it => it.system.frequence, filter = it => true) {
+ return await SystemCompendiums.getContent(this.compendium,
+ this.type,
+ it => this.subType == it.type && filter(it),
+ itemFrequence,
+ this.sorting);
}
- async getRandom(toChat = true, itemFrequence = it => it.system.frequence, filter = it => true, forcedRoll = undefined) {
- const table = await this.$buildTable(itemFrequence, filter);
+ async buildTable(itemFrequence = it => it.system.frequence, filter = it => true) {
+ const elements = await this.getContent(filter, itemFrequence);
+ return CompendiumTableHelpers.buildTable(elements, itemFrequence);
+ }
+
+ async getRandom(itemFrequence = it => it.system.frequence, filter = it => true, forcedRoll = undefined) {
+ const table = await this.buildTable(itemFrequence, filter);
+ return await CompendiumTableHelpers.getRandom(table, this.type, this.subType, forcedRoll, SystemCompendiums.getCompendium(compendium));
+ }
+
+ async toChatMessage(itemFrequence = it => it.system.frequence, filter = it => true, typeName = undefined) {
+ const table = await this.buildTable(itemFrequence, filter);
+ await CompendiumTableHelpers.tableToChatMessage(table, this.type, this.subType, typeName);
+ return true;
+ }
+}
+
+/**
+ * ======= Gestion de tables correspondant à un compendium =======
+ */
+export class CompendiumTableHelpers {
+
+ static buildTable(elements, itemFrequence) {
+ let max = 0;
+ const total = elements.map(it => itemFrequence(it)).reduce(Misc.sum(), 0);
+ return elements.map(it => {
+ const frequence = itemFrequence(it);
+ let row = { document: it, frequence: frequence, min: max + 1, max: max + frequence, total: total };
+ max += frequence;
+ return row;
+ });
+ }
+
+ static async getRandom(table, type, subType, forcedRoll = undefined, localisation = undefined) {
if (table.length == 0) {
- ui.notifications.warn(`Aucun ${this.typeName()} dans ${this.sourceCompendium}`);
+ ui.notifications.warn(`Aucun ${Misc.typeName(type, subType)} trouvé dans ${localisation ?? ' les compendiums'}`);
return undefined;
}
- const row = await this.$selectRow(table, forcedRoll);
- if (row && toChat) {
- await this.$chatRolledResult(row);
- }
- return row;
- }
-
- async chatTable(itemFrequence = it => it.system.frequence, filter = it => true, typeName = undefined) {
- const table = await this.$buildTable(itemFrequence, filter);
- await this.$chatSystemCompendiumTable(table, typeName);
- }
-
- async $buildTable(itemFrequence, filter) {
- return await SystemCompendiums.buildTable(this.compendium, itemFrequence, this.applyType(filter), this.type, this.sorting);
+ return await CompendiumTableHelpers.selectRow(table, forcedRoll);
}
/* -------------------------------------------- */
- async $selectRow(table, forcedRoll = undefined) {
+ static async selectRow(table, forcedRoll = undefined) {
if (table.length == 0) {
return undefined
}
@@ -238,14 +246,16 @@ export class SystemCompendiumTable {
}
/* -------------------------------------------- */
- async $chatRolledResult(row) {
+ static async tableRowToChatMessage(row, type = 'Item') {
+ if (!row) {
+ return;
+ }
const percentages = (row.total == 100) ? '%' : ''
const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table-roll.html', {
roll: row.roll,
- document: row?.document,
+ document: row.document,
percentages,
- typeName: this.typeName(),
- sourceCompendium: this.sourceCompendium,
+ typeName: Misc.typeName(type, row.document.type),
isGM: game.user.isGM,
});
const messageData = {
@@ -260,11 +270,10 @@ export class SystemCompendiumTable {
}
/* -------------------------------------------- */
- async $chatSystemCompendiumTable(table, typeName) {
+ static async tableToChatMessage(table, type, subType, typeName = undefined) {
const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table.html', {
- img: RdDItem.getDefaultImg(this.subType),
- typeName: typeName ?? this.typeName(),
- sourceCompendium: this.sourceCompendium,
+ img: RdDItem.getDefaultImg(subType),
+ typeName: typeName ?? Misc.typeName(type, subType),
table,
isGM: game.user.isGM,
});
@@ -275,5 +284,4 @@ export class SystemCompendiumTable {
}, { rollMode: "gmroll" });
}
-
-}
+}
\ No newline at end of file
diff --git a/module/tmr-rencontres.js b/module/tmr-rencontres.js
index 44cb488e..0bbe46b3 100644
--- a/module/tmr-rencontres.js
+++ b/module/tmr-rencontres.js
@@ -1,7 +1,7 @@
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
-import { SystemCompendiums, SystemCompendiumTable } from "./settings/system-compendiums.js";
+import { SystemCompendiums, CompendiumTable, CompendiumTableHelpers } from "./settings/system-compendiums.js";
import { TMRUtility } from "./tmr-utility.js";
@@ -15,7 +15,7 @@ export class TMRRencontres {
}
constructor(){
- this.table = new SystemCompendiumTable('rencontres', 'Item', 'rencontre', Misc.ascending(it => it.system.ordreTri));
+ this.table = new CompendiumTable('rencontres', 'Item', 'rencontre', Misc.ascending(it => it.system.ordreTri));
}
/* -------------------------------------------- */
@@ -36,9 +36,12 @@ export class TMRRencontres {
const codeTerrain = Grammar.toLowerCaseNoAccent(terrain)
const filtreMauvaise = codeTerrain == 'mauvaise' ? it => it.system.mauvaiseRencontre : it => !it.system.mauvaiseRencontre;
const frequence = it => it.system.frequence[codeTerrain];
- const random = await this.table.getRandom(true, frequence, filtreMauvaise, forcedRoll);
+ const row = await this.table.getRandom(frequence, filtreMauvaise, forcedRoll);
+ if (row) {
+ await CompendiumTableHelpers.tableRowToChatMessage(row);
+ }
- return random?.document;
+ return row?.document;
}
async chatTable(terrain) {
@@ -47,9 +50,9 @@ export class TMRRencontres {
const filtreMauvaise = isMauvaise ? it => it.system.mauvaiseRencontre : it => !it.system.mauvaiseRencontre;
const frequence = it => it.system.frequence[codeTerrain];
const typeName = isMauvaise ? 'Mauvaises rencontres' : `Rencontres en ${Misc.upperFirst(terrain)}`;
- await this.table.chatTable(frequence, filtreMauvaise, typeName);
- return true
+ return await this.table.toChatMessage(frequence, filtreMauvaise, typeName);
}
+
/* -------------------------------------------- */
async createRencontre(rencontre, tmr = undefined) {
return rencontre.clone({
@@ -95,7 +98,7 @@ export class TMRRencontres {
const filtreMauvaise = codeTerrain == 'mauvaise' ? it => it.system.mauvaiseRencontre : it => !it.system.mauvaiseRencontre;
const frequence = it => it.system.frequence[codeTerrain];
- const row = await this.table.getRandom(false, frequence, filtreMauvaise);
+ const row = await this.table.getRandom(frequence, filtreMauvaise);
if (row) {
row.document = this.createRencontre(row.document, tmr);
await this.$chatRolledRencontre(row, tmr);
diff --git a/styles/simple.css b/styles/simple.css
index fb8213c6..2c69cd41 100644
--- a/styles/simple.css
+++ b/styles/simple.css
@@ -1738,7 +1738,41 @@ display: inline-flex;
/* Change color of dropdown links on hover */
.button-dropdown-content a:hover {background-color: #ddd;}
+/* ======== autocomplete ======= */
+.autocomplete {
+ position: relative;
+ display: inline-block;
+}
+.autocomplete-items {
+ position: absolute;
+ border: 1px solid var(--color-border-dark);
+ border-bottom: none;
+ border-top: none;
+ z-index: 99;
+ /*position the autocomplete items to be the same width as the container:*/
+ top: 100%;
+ left: 0;
+ right: 0;
+}
+
+.autocomplete-items div {
+ padding: 10px;
+ cursor: pointer;
+ background-color: #fff;
+ border-bottom: 1px solid #d4d4d4;
+}
+
+/*when hovering an item:*/
+.autocomplete-items div:hover {
+ background-color: #e9e9e9;
+}
+
+/*when navigating through the items using the arrow keys:*/
+.autocomplete-active {
+ background-color: DodgerBlue !important;
+ color: #ffffff;
+}
/*************************************************************/
#pause
diff --git a/template.json b/template.json
index 4321104c..27c37132 100644
--- a/template.json
+++ b/template.json
@@ -591,6 +591,10 @@
"quantite": 1,
"qualite": 0,
"cout": 0
+ },
+ "environnement": {
+ "milieu": "",
+ "environnement": []
}
},
"competence": {
@@ -704,19 +708,15 @@
"exotisme": 0
},
"herbe": {
- "templates": [ "description", "inventaire" ],
+ "templates": [ "description", "inventaire", "environnement"],
"niveau": 0,
"base": 0,
- "milieu": "",
- "rarete": "",
"categorie": ""
},
"ingredient": {
- "templates": [ "description", "inventaire" ],
+ "templates": [ "description", "inventaire", "environnement" ],
"niveau": 0,
"base": 0,
- "milieu": "",
- "rarete": "",
"categorie": ""
},
"livre": {
diff --git a/templates/chat-compendium-table-roll-rencontre.html b/templates/chat-compendium-table-roll-rencontre.html
index bb951c88..2b724e95 100644
--- a/templates/chat-compendium-table-roll-rencontre.html
+++ b/templates/chat-compendium-table-roll-rencontre.html
@@ -1,11 +1,11 @@
{{rencontre.name}} {{rencontre.system.force}} ({{rencontre.system.formule}})
-{{linkCompendium sourceCompendium rencontre.id rencontre.name}}
+{{linkCompendium rencontre.pack rencontre.id rencontre.name}}
{{#if rencontre.system.description}}{{linkCompendium @root.sourceCompendium document.id document.name}}
+{{linkCompendium document.pack document.id document.name}}
{{#if document.system.description}}