From b7a0e5d03471d137ccce2f0bf100c2154450e86b Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Mon, 28 Nov 2022 11:31:19 +0100 Subject: [PATCH] =?UTF-8?q?Fr=C3=A9quences=20par=20milieu=20pour=20l'envir?= =?UTF-8?q?onnement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les herbes et les ingrédients peuvent être cherchées/tirées --- module/environnement.js | 222 ++++++++++++++++++ module/item-herbe-sheet.js | 45 ++++ module/item-ingredient-sheet.js | 44 ++++ module/migrations.js | 32 ++- module/rdd-commands.js | 26 +- module/rdd-main.js | 8 +- module/rdd-rolltables.js | 23 +- module/rdd-utility.js | 8 +- module/settings/system-compendiums.js | 130 +++++----- module/tmr-rencontres.js | 17 +- styles/simple.css | 34 +++ template.json | 12 +- .../chat-compendium-table-roll-rencontre.html | 4 +- templates/chat-compendium-table-roll.html | 4 +- templates/chat-compendium-table.html | 8 +- templates/enum-rarete.html | 1 - templates/item-herbe-sheet.html | 53 ++--- templates/item-ingredient-sheet.html | 50 ++-- templates/item-potion-sheet.html | 1 + templates/item/partial-environnement.html | 36 +++ templates/item/partial-tab-environnement.html | 1 + templates/scripts/autocomplete-script.hbs | 96 ++++++++ templates/scripts/autocomplete.hbs | 5 + 23 files changed, 702 insertions(+), 158 deletions(-) create mode 100644 module/environnement.js create mode 100644 module/item-herbe-sheet.js create mode 100644 module/item-ingredient-sheet.js create mode 100644 templates/item/partial-environnement.html create mode 100644 templates/item/partial-tab-environnement.html create mode 100644 templates/scripts/autocomplete-script.hbs create mode 100644 templates/scripts/autocomplete.hbs 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}}

{{#if mauvaise}}Mauvaise rencontre{{else}}Rencontre{{/if}} en {{typeTmr-name tmr.type}}

-
{{sourceCompendium}}
+
{{rencontre.pack}}
Jet: {{roll.formula}} : {{roll.total}}{{percentages}}

{{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}}
{{{rencontre.system.description}}} diff --git a/templates/chat-compendium-table-roll.html b/templates/chat-compendium-table-roll.html index c131780d..a317d31c 100644 --- a/templates/chat-compendium-table-roll.html +++ b/templates/chat-compendium-table-roll.html @@ -1,10 +1,10 @@

Tirage aléatoire: {{typeName}}

-
{{sourceCompendium}}
+
{{document.pack}}
Jet {{roll.formula}} : {{roll.total}}{{percentages}}

{{document.name}} -

{{linkCompendium @root.sourceCompendium document.id document.name}}

+

{{linkCompendium document.pack document.id document.name}}

{{#if document.system.description}}
{{{document.system.description}}} diff --git a/templates/chat-compendium-table.html b/templates/chat-compendium-table.html index caef27d8..198323a8 100644 --- a/templates/chat-compendium-table.html +++ b/templates/chat-compendium-table.html @@ -1,7 +1,11 @@
{{typeName}}

Table aléatoire: {{typeName}}

-
{{sourceCompendium}}
+ {{#with (lookup table 0) as |row|}} +
+ {{row.document.pack}} +
+ {{/with}}
@@ -9,7 +13,7 @@ {{#each table as |row|}}
  • {{row.min}}{{#unless (eq row.min row.max)}}-{{row.max}}{{/unless}} :   - {{linkCompendium @root.sourceCompendium row.document.id row.document.name}} + {{linkCompendium row.document.pack row.document.id row.document.name}}
  • {{/each}} diff --git a/templates/enum-rarete.html b/templates/enum-rarete.html index 667b2c76..f7fdc4ba 100644 --- a/templates/enum-rarete.html +++ b/templates/enum-rarete.html @@ -1,4 +1,3 @@ - diff --git a/templates/item-herbe-sheet.html b/templates/item-herbe-sheet.html index 8f520f64..da561fee 100644 --- a/templates/item-herbe-sheet.html +++ b/templates/item-herbe-sheet.html @@ -11,38 +11,31 @@
    - {{!-- Sheet Body --}} + +
    -
    -
    - - +
    +
    +
    + + +
    +
    + + +
    + + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.html"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.html"}}
    -
    - - -
    -
    - - -
    -
    - - -
    - - {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.html"}} - {{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.html"}} -
    + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-environnement.html"}}
    - \ No newline at end of file diff --git a/templates/item-ingredient-sheet.html b/templates/item-ingredient-sheet.html index 66035c4b..687e3f88 100644 --- a/templates/item-ingredient-sheet.html +++ b/templates/item-ingredient-sheet.html @@ -1,34 +1,28 @@
    {{>"systems/foundryvtt-reve-de-dragon/templates/header-item.html"}} - {{!-- Sheet Body --}} -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    + - {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.html"}} - {{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.html"}} +
    +
    +
    + + +
    +
    + + +
    + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.html"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.html"}} +
    + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-environnement.html"}}
    \ No newline at end of file diff --git a/templates/item-potion-sheet.html b/templates/item-potion-sheet.html index 282e36fd..f696d0e5 100644 --- a/templates/item-potion-sheet.html +++ b/templates/item-potion-sheet.html @@ -17,6 +17,7 @@ diff --git a/templates/item/partial-environnement.html b/templates/item/partial-environnement.html new file mode 100644 index 00000000..df0ab650 --- /dev/null +++ b/templates/item/partial-environnement.html @@ -0,0 +1,36 @@ +{{>'systems/foundryvtt-reve-de-dragon/templates/scripts/autocomplete-script.hbs'}} + +
    +
    + + +
    +
    +
    + +
    +
    + +
    + {{>'systems/foundryvtt-reve-de-dragon/templates/scripts/autocomplete.hbs' proposals=milieux className='input-selection-milieu'}} + +
    +
    + {{#each system.environnement as |env|}} +
    + +
    + + {{rangePicker name="environnement-frequence" value=env.frequence min=(getFrequenceRarete env.rarete 'min') max=(getFrequenceRarete env.rarete 'max') step=1}} + +
    +
    + {{/each}} +
    \ No newline at end of file diff --git a/templates/item/partial-tab-environnement.html b/templates/item/partial-tab-environnement.html new file mode 100644 index 00000000..4154ef58 --- /dev/null +++ b/templates/item/partial-tab-environnement.html @@ -0,0 +1 @@ +Environnement diff --git a/templates/scripts/autocomplete-script.hbs b/templates/scripts/autocomplete-script.hbs new file mode 100644 index 00000000..7f918b6c --- /dev/null +++ b/templates/scripts/autocomplete-script.hbs @@ -0,0 +1,96 @@ + diff --git a/templates/scripts/autocomplete.hbs b/templates/scripts/autocomplete.hbs new file mode 100644 index 00000000..82d5b4b5 --- /dev/null +++ b/templates/scripts/autocomplete.hbs @@ -0,0 +1,5 @@ +