forked from public/foundryvtt-reve-de-dragon
		
	Import de foundry.applications.handlebars.renderTemplate au travers d'une constante pour éliminer les warnings
		
			
				
	
	
		
			326 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			326 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import { ChatUtility } from "../chat-utility.js";
 | |
| import { HIDE_DICE, renderTemplate, SYSTEM_RDD } from "../constants.js";
 | |
| import { Grammar } from "../grammar.js";
 | |
| import { RdDItem } from "../item.js";
 | |
| import { Misc } from "../misc.js";
 | |
| import { RdDDice } from "../rdd-dice.js";
 | |
| 
 | |
| const COMPENDIUM_SETTING_PREFIX = 'compendium-';
 | |
| 
 | |
| const CONFIGURABLE_COMPENDIUMS = {
 | |
|   'tables-diverses': { label: "Tables aléatoires", type: "RollTable" },
 | |
|   'competences': { label: "Compétences", type: "Item" },
 | |
|   'extrait-poetique': { label: "Extraits poetiques", type: "Item" },
 | |
|   'queues-de-dragon': { label: "Queues de dragon", type: "Item" },
 | |
|   'ombres-de-thanatos': { label: "Ombres de Thanatos", type: "Item" },
 | |
|   'souffles-de-dragon': { label: "Souffles de Dragon", type: "Item" },
 | |
|   'tarot-draconique': { label: "Tarots draconiques", type: "Item" },
 | |
|   'races': { label: "Races", type: "Item" },
 | |
|   '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" },
 | |
|   'faune-flore-mineraux': { 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 initSettings() {
 | |
|     Object.keys(CONFIGURABLE_COMPENDIUMS).forEach(compendium => {
 | |
|       const definition = CONFIGURABLE_COMPENDIUMS[compendium];
 | |
|       foundry.utils.mergeObject(definition, {
 | |
|         compendium: compendium,
 | |
|         default: SystemCompendiums._getDefaultCompendium(compendium),
 | |
|         setting: SystemCompendiums._getSettingCompendium(compendium)
 | |
|       })
 | |
| 
 | |
|       game.settings.register(SYSTEM_RDD, definition.setting, {
 | |
|         name: definition.label,
 | |
|         default: definition.default,
 | |
|         scope: "world",
 | |
|         config: false,
 | |
|         type: String
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     game.settings.registerMenu(SYSTEM_RDD, "compendium-settings", {
 | |
|       name: "Choisir les compendiums système",
 | |
|       label: "Compendiums système",
 | |
|       hint: "Ouvre la fenêtre de sélection des compendiums système",
 | |
|       icon: "fas fa-bars",
 | |
|       restricted: true,
 | |
|       type: SystemCompendiums
 | |
|     })
 | |
|   }
 | |
| 
 | |
|   static getPack(compendium) {
 | |
|     const pack = game.packs.get(compendium);
 | |
|     if (pack) {
 | |
|       return pack;
 | |
|     }
 | |
|     return game.packs.get(SystemCompendiums.getCompendium(compendium)) ?? game.packs.get(SystemCompendiums._getDefaultCompendium(compendium));
 | |
|   }
 | |
| 
 | |
|   static async getPackContent(compendium, docType) {
 | |
|     const pack = SystemCompendiums.getPack(compendium);
 | |
|     if (pack?.metadata.type == docType) {
 | |
|       return await pack.getDocuments();
 | |
|     }
 | |
|     return [];
 | |
|   }
 | |
| 
 | |
|   static async getCompetences(actorType) {
 | |
|     switch (actorType ?? 'personnage') {
 | |
|       case 'personnage':
 | |
|         return await SystemCompendiums.getWorldOrCompendiumItems('competence', 'competences')
 | |
|       case 'entite':
 | |
|       case 'creature':
 | |
|         return await SystemCompendiums.getWorldOrCompendiumItems('competencecreature', 'competences-creatures')
 | |
|       case 'vehicule': return [];
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* -------------------------------------------- */
 | |
|   static async getWorldOrCompendiumItems(itemType, compendium) {
 | |
|     let items = game.items.filter(it => it.type == itemType)
 | |
|     if (compendium) {
 | |
|       const ids = items.map(it => it.id)
 | |
|       const names = items.map(it => Grammar.toLowerCaseNoAccent(it.name))
 | |
|       const compendiumItems = await SystemCompendiums.getItems(compendium, itemType)
 | |
|       return items.concat(compendiumItems
 | |
|         .filter(it => !ids.includes(it.id))
 | |
|         .filter(it => !names.includes(Grammar.equalsInsensitive(it.name))))
 | |
|     }
 | |
|     return items
 | |
|   }
 | |
| 
 | |
|   static async loadDocument(document) {
 | |
|     const pack = game.packs.get(document.pack);
 | |
|     return await pack.getDocument(document.id ?? document._id);
 | |
|   }
 | |
| 
 | |
|   static async getItems(compendium, itemType = undefined) {
 | |
|     const items = await SystemCompendiums.getPackContent(compendium, 'Item');
 | |
|     return (itemType ? items.filter(it => it.type == itemType) : items);
 | |
|   }
 | |
| 
 | |
|   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);
 | |
|     }
 | |
|     return elements;
 | |
|   }
 | |
| 
 | |
|   /* -------------------------------------------- */
 | |
|   static async loadCompendiumData(compendium) {
 | |
|     const pack = game.packs.get(compendium);
 | |
|     return await pack?.getDocuments() ?? [];
 | |
|   }
 | |
| 
 | |
|   /* -------------------------------------------- */
 | |
|   static async loadCompendium(compendium, filter = item => true) {
 | |
|     let compendiumData = await SystemCompendiums.loadCompendiumData(compendium);
 | |
|     return compendiumData.filter(filter);
 | |
|   }
 | |
| 
 | |
| 
 | |
|   static async getDefaultItems(compendium) {
 | |
|     const pack = game.packs.get(SystemCompendiums._getDefaultCompendium(compendium));
 | |
|     if (pack.metadata.type == 'Item') {
 | |
|       return await pack.getDocuments();
 | |
|     }
 | |
|     return [];
 | |
|   }
 | |
| 
 | |
|   static getCompendium(compendium) {
 | |
|     const setting = CONFIGURABLE_COMPENDIUMS[compendium]?.setting;
 | |
|     return setting ? game.settings.get(SYSTEM_RDD, setting) : SystemCompendiums._getDefaultCompendium(compendium);
 | |
|   }
 | |
| 
 | |
|   static _getSettingCompendium(compendium) {
 | |
|     return COMPENDIUM_SETTING_PREFIX + compendium;
 | |
|   }
 | |
| 
 | |
|   static _getDefaultCompendium(compendium) {
 | |
|     return `${SYSTEM_RDD}.${compendium}`;
 | |
|   }
 | |
| 
 | |
|   constructor(...args) {
 | |
|     super(...args);
 | |
|   }
 | |
| 
 | |
|   static get defaultOptions() {
 | |
|     const options = super.defaultOptions;
 | |
|     foundry.utils.mergeObject(options, {
 | |
|       id: "system-compendiums",
 | |
|       template: "systems/foundryvtt-reve-de-dragon/templates/settings/system-compendiums.hbs",
 | |
|       height: 'fit-content',
 | |
|       width: 600,
 | |
|       minimizable: false,
 | |
|       closeOnSubmit: true,
 | |
|       title: "Compendiums système"
 | |
|     });
 | |
|     return options;
 | |
|   }
 | |
| 
 | |
|   getData() {
 | |
|     const systemCompendiums = Object.values(CONFIGURABLE_COMPENDIUMS)
 | |
|       .map(it => foundry.utils.mergeObject(it, { value: SystemCompendiums.getCompendium(it.compendium) }, { inplace: false }))
 | |
|     const availableCompendiums = game.packs.map(pack => {
 | |
|       return {
 | |
|         name: pack.collection,
 | |
|         path: pack.collection.replace('.', " / "),
 | |
|         type: pack.metadata.type
 | |
|       }
 | |
|     });
 | |
|     return foundry.utils.mergeObject(super.getData(), {
 | |
|       systemCompendiums: systemCompendiums,
 | |
|       availableCompendiums: availableCompendiums
 | |
|     }, { inplace: false })
 | |
|   }
 | |
| 
 | |
|   activateListeners(html) {
 | |
|     $(html).find("select.system-compendium-setting").change((event) => {
 | |
|       const compendium = $(event.currentTarget).data('compendium')
 | |
|       const value = $(event.currentTarget).val();
 | |
|       const systemCompendium = CONFIGURABLE_COMPENDIUMS[compendium];
 | |
| 
 | |
|       game.settings.set(SYSTEM_RDD, systemCompendium.setting, value);
 | |
|     });
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ======= Gestion de jets dans une table correspondant à un compendium =======
 | |
|  */
 | |
| export class CompendiumTable {
 | |
| 
 | |
|   constructor(compendium, type, subTypes = undefined, sorting = undefined) {
 | |
|     this.compendium = compendium;
 | |
|     this.type = type;
 | |
|     this.subTypes = subTypes;
 | |
|     this.sorting = sorting ?? Misc.ascending(it => it.name);
 | |
|   }
 | |
| 
 | |
|   async getContent(itemFrequence = it => it.system.frequence, filter = it => true) {
 | |
|     return await SystemCompendiums.getContent(this.compendium,
 | |
|       this.type,
 | |
|       it => (!this.subTypes || this.subTypes.includes(it.type)) && itemFrequence(it) > 0 && filter(it),
 | |
|       itemFrequence,
 | |
|       this.sorting);
 | |
|   }
 | |
| 
 | |
|   async buildTable(itemFrequence = it => it.system.frequence, filter = it => true) {
 | |
|     const elements = await this.getContent(itemFrequence, filter);
 | |
|     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.subTypes, 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.subTypes, 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 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) {
 | |
|       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);
 | |
|   }
 | |
| 
 | |
|   /* -------------------------------------------- */
 | |
|   static async selectRow(table, forcedRoll = undefined) {
 | |
|     if (table.length == 0) {
 | |
|       return undefined
 | |
|     }
 | |
|     const total = table[0].total;
 | |
|     const formula = `1d${total}`;
 | |
|     if (forcedRoll != undefined && (forcedRoll > total || forcedRoll <= 0)) {
 | |
|       ui.notifications.warn(`Jet forcé ${forcedRoll} en dehors de la table [1..${total}], le jet est relancé`);
 | |
|       forcedRoll = undefined;
 | |
|     }
 | |
|     const roll = forcedRoll ? { total: forcedRoll, formula } : await RdDDice.roll(formula, { showDice: HIDE_DICE });
 | |
|     const row = table.find(it => it.min <= roll.total && roll.total <= it.max);
 | |
|     row.roll = roll;
 | |
|     return row;
 | |
|   }
 | |
| 
 | |
|   /* -------------------------------------------- */
 | |
|   static async tableRowToChatMessage(row, type, options = { showSource: true }) {
 | |
|     if (!row) {
 | |
|       return;
 | |
|     }
 | |
|     const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table-roll.hbs', {
 | |
|       roll: row.roll,
 | |
|       document: row.document,
 | |
|       typeName: Misc.typeName(type, row.document?.type ?? 'objet'),
 | |
|       isGM: game.user.isGM,
 | |
|       options
 | |
|     });
 | |
|     const messageData = {
 | |
|       user: game.user.id,
 | |
|       rolls: [row.roll],
 | |
|       sound: CONFIG.sounds.dice,
 | |
|       content: flavorContent
 | |
|     };
 | |
|     await ChatUtility.createChatWithRollMode(messageData)
 | |
|   }
 | |
| 
 | |
|   /* -------------------------------------------- */
 | |
|   static async tableToChatMessage(table, type, subTypes, typeName = undefined) {
 | |
|     const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table.hbs', {
 | |
|       img: RdDItem.getDefaultImg(subTypes[0]),
 | |
|       typeName: typeName ?? Misc.typeName(type, subTypes[0]),
 | |
|       table,
 | |
|       isGM: game.user.isGM,
 | |
|     });
 | |
|     const messageData = {
 | |
|       user: game.user.id,
 | |
|       whisper: [game.user],
 | |
|       content: flavorContent
 | |
|     };
 | |
|     await ChatUtility.createChatWithRollMode(messageData)
 | |
|   }
 | |
| 
 | |
| } |