Vincent Vandemeulebrouck
2fa0ce5f15
L'item "race" permet de paramétrer des ajustements de caracs, des min/max de taille, et une limite de force. Ajouter une race à un acteur enlève la/les races précédentes et ajoute les modificateurs de caracs de la nouvelle race. Enlever une race enlève les modificateurs de caracs de la race aux caractéristiques
326 lines
12 KiB
JavaScript
326 lines
12 KiB
JavaScript
import { ChatUtility } from "../chat-utility.js";
|
|
import { HIDE_DICE, 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.html",
|
|
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)
|
|
}
|
|
|
|
} |