diff --git a/module/migrations.js b/module/migrations.js index 5f2e8d36..f2765567 100644 --- a/module/migrations.js +++ b/module/migrations.js @@ -29,6 +29,39 @@ class Migration { } +class _1_5_34_migrationPngWebp { + get code() { return "migrationPngWebp"; } + get version() { return "1.5.34"; } + async migrate() { + + const regexOldPngJpg = /(systems\/foundryvtt-reve-de-dragon\/icons\/.*)\.(png|jpg)/; + const replaceWithWebp = '$1.webp'; + function convertImgToWebp(img) { + return img.replace(regexOldPngJpg, replaceWithWebp); + } + function prepareDocumentsImgUpdate(documents) { + return documents.filter(it => it.img && it.img.match(regexOldPngJpg)) + .map(it => { + return { _id: it.id, img: convertImgToWebp(it.img) } + }); + } + + const itemsUpdates = prepareDocumentsImgUpdate(game.items); + const actorsUpdates = prepareDocumentsImgUpdate(game.actors); + //Migrate system png to webp + await Item.updateDocuments(itemsUpdates); + await Actor.updateDocuments(actorsUpdates); + game.actors.forEach(actor => { + if (actor.token?.img && actor.token.img.match(regexOldPngJpg)) { + actor.update({ "token.img": convertImgToWebp(actor.token.img) }); + } + const actorItemsToUpdate = prepareDocumentsImgUpdate(actor.items); + actor.updateEmbeddedDocuments('Item', actorItemsToUpdate); + }); + } +} + + class _10_0_16_MigrationSortsReserve extends Migration { get code() { return "creation-item-sort-reserve"; } get version() { return "10.0.16"; } @@ -296,6 +329,7 @@ class _10_3_17_Monnaies extends Migration { export class Migrations { static getMigrations() { return [ + new _1_5_34_migrationPngWebp(), new _10_0_16_MigrationSortsReserve(), new _10_0_17_MigrationCompetenceCreature(), new _10_0_21_VehiculeStructureResistanceMax(), diff --git a/module/rdd-hotbar-drop.js b/module/rdd-hotbar-drop.js index 4bef344f..e2963f64 100644 --- a/module/rdd-hotbar-drop.js +++ b/module/rdd-hotbar-drop.js @@ -1,4 +1,3 @@ -import { Misc } from "./misc.js"; export class RdDHotbar { diff --git a/module/rdd-main.js b/module/rdd-main.js index da4bf7bf..c7d5b212 100644 --- a/module/rdd-main.js +++ b/module/rdd-main.js @@ -1,13 +1,3 @@ -/** - * RdD system - * Author: LeRatierBretonnien - * Software License: GNU GPLv3 - */ - -/* -------------------------------------------- */ - -/* -------------------------------------------- */ -// Import Modules import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; import { RdDActor } from "./actor.js"; import { RdDItemSheet } from "./item-sheet.js"; @@ -45,301 +35,272 @@ import { RdDIngredientItemSheet } from "./item-ingredient-sheet.js"; import { RdDFauneItemSheet } from "./item-faune-sheet.js"; import { RdDConteneurItemSheet } from "./item-conteneur-sheet.js"; -/* -------------------------------------------- */ -/* Foundry VTT Initialization */ -/* -------------------------------------------- */ +/** + * RdD system + * Author: LeRatierBretonnien + * Software License: GNU GPLv3 + */ +export class SystemReveDeDragon { + static start() { + const system = new SystemReveDeDragon(); + Hooks.once('init', async () => await system.onInit()); + Hooks.once('diceSoNiceReady', (dice3d) => RdDDice.diceSoNiceReady(dice3d)); + } - -/************************************************************************************/ -Hooks.once("init", async function () { - console.log(`Initializing Reve de Dragon System`); - - // preload handlebars templates - RdDUtility.preloadHandlebarsTemplates(); - // Create useful storage space - game.system.rdd = { - TMRUtility, - RdDUtility, - RdDHotbar, - RdDPossession, + constructor() { + this.RdDUtility = RdDUtility; + this.RdDHotbar = RdDHotbar; } /* -------------------------------------------- */ - game.settings.register(SYSTEM_RDD, "accorder-entite-cauchemar", { - name: "Accorder le rêve aux entités", - hint: "A quel moment les personnages doivent accorder leur rêve aux entités de cauchemar", - scope: "world", - config: true, - type: String, - choices: { // If choices are defined, the resulting setting will be a select menu - "avant-attaque": "Avant l'attaque", - "avant-defense": "Avant la défense", - "avant-encaissement": "Avant l'encaissement", - }, - default: "avant-encaissement" - }); - + /* Foundry VTT Initialization */ /* -------------------------------------------- */ - game.settings.register(SYSTEM_RDD, "calendrier", { - name: "calendrier", - scope: "world", - config: false, - default: RdDCalendrier.createCalendrierInitial(), - type: Object - }); + async onInit() { + game.system.rdd = this; - /* -------------------------------------------- */ - game.settings.register(SYSTEM_RDD, "migration-png-webp-1.5.34", { - name: "calendrier", - scope: "world", - config: false, - default: false, - type: Boolean - }); + console.log(`Initializing Reve de Dragon System`); - /* -------------------------------------------- */ - game.settings.register(SYSTEM_RDD, "liste-nombre-astral", { - name: "liste-nombre-astral", - scope: "world", - config: false, - default: [], - type: Object - }); + // preload handlebars templates + RdDUtility.preloadHandlebarsTemplates(); - /* -------------------------------------------- */ - game.settings.register(SYSTEM_RDD, "calendrier-pos", { - name: "calendrierPos", - scope: "client", - config: false, - default: RdDCalendrier.createCalendrierPos(), - type: Object - }); + /* -------------------------------------------- */ + game.settings.register(SYSTEM_RDD, "accorder-entite-cauchemar", { + name: "Accorder le rêve aux entités", + hint: "A quel moment les personnages doivent accorder leur rêve aux entités de cauchemar", + scope: "world", + config: true, + type: String, + choices: { // If choices are defined, the resulting setting will be a select menu + "avant-attaque": "Avant l'attaque", + "avant-defense": "Avant la défense", + "avant-encaissement": "Avant l'encaissement", + }, + default: "avant-encaissement" + }); + + /* -------------------------------------------- */ + game.settings.register(SYSTEM_RDD, "calendrier", { + name: "calendrier", + scope: "world", + config: false, + default: RdDCalendrier.createCalendrierInitial(), + type: Object + }); + + /* -------------------------------------------- */ + game.settings.register(SYSTEM_RDD, "liste-nombre-astral", { + name: "liste-nombre-astral", + scope: "world", + config: false, + default: [], + type: Object + }); + + /* -------------------------------------------- */ + game.settings.register(SYSTEM_RDD, "calendrier-pos", { + name: "calendrierPos", + scope: "client", + config: false, + default: RdDCalendrier.createCalendrierPos(), + type: Object + }); - /* -------------------------------------------- */ - game.settings.register(SYSTEM_RDD, "supprimer-dialogues-combat-chat", { - name: "Supprimer les dialogues de combat", - hint: "Si désactivée, tous les dialogues de combat sont conservés dans la conversation", - scope: "world", - config: true, - default: true, - type: Boolean - }); - /* -------------------------------------------- */ - game.settings.register(SYSTEM_RDD, "activer-sons-audio", { - name: "Activer les bruitages intégrés", - hint: "Si activé, certaines actions en jeu déclenchent un son d'ambiance", - scope: "world", - config: true, - default: true, - type: Boolean - }); - /* -------------------------------------------- */ - game.settings.register(SYSTEM_RDD, "appliquer-famine-soif", { - name: "Notifier de la famine et la soif pour", - hint: "Indique si les cas de famine et de soif seront indiqués durant Château Dormant", - scope: "world", - config: true, - type: String, - choices: { - "aucun": "ni la famine, ni la soif", - "famine": "seulement la famine", - "famine-soif": "la famine et la soif", - }, - default: "aucun" - }); + /* -------------------------------------------- */ + game.settings.register(SYSTEM_RDD, "supprimer-dialogues-combat-chat", { + name: "Supprimer les dialogues de combat", + hint: "Si désactivée, tous les dialogues de combat sont conservés dans la conversation", + scope: "world", + config: true, + default: true, + type: Boolean + }); + /* -------------------------------------------- */ + game.settings.register(SYSTEM_RDD, "activer-sons-audio", { + name: "Activer les bruitages intégrés", + hint: "Si activé, certaines actions en jeu déclenchent un son d'ambiance", + scope: "world", + config: true, + default: true, + type: Boolean + }); + /* -------------------------------------------- */ + game.settings.register(SYSTEM_RDD, "appliquer-famine-soif", { + name: "Notifier de la famine et la soif pour", + hint: "Indique si les cas de famine et de soif seront indiqués durant Château Dormant", + scope: "world", + config: true, + type: String, + choices: { + "aucun": "ni la famine, ni la soif", + "famine": "seulement la famine", + "famine-soif": "la famine et la soif", + }, + default: "aucun" + }); - /* -------------------------------------------- */ - // Set an initiative formula for the system - CONFIG.Combat.initiative = { - formula: "1+(1d6/10)", - decimals: 2 - }; + /* -------------------------------------------- */ + // Set an initiative formula for the system + CONFIG.Combat.initiative = { + formula: "1+(1d6/10)", + decimals: 2 + }; - /* -------------------------------------------- */ - game.socket.on(SYSTEM_SOCKET_ID, async (sockmsg) => { - console.log(">>>>> MSG RECV", sockmsg); - try { - RdDUtility.onSocketMessage(sockmsg); - RdDCombat.onSocketMessage(sockmsg); - ChatUtility.onSocketMessage(sockmsg); - RdDActor.onSocketMessage(sockmsg); - } catch (e) { - console.error('game.socket.on(SYSTEM_SOCKET_ID) Exception: ', sockmsg, ' => ', e) + /* -------------------------------------------- */ + game.socket.on(SYSTEM_SOCKET_ID, async (sockmsg) => { + console.log(">>>>> MSG RECV", sockmsg); + try { + RdDUtility.onSocketMessage(sockmsg); + RdDCombat.onSocketMessage(sockmsg); + ChatUtility.onSocketMessage(sockmsg); + RdDActor.onSocketMessage(sockmsg); + } catch (e) { + console.error('game.socket.on(SYSTEM_SOCKET_ID) Exception: ', sockmsg, ' => ', e) + } + }); + + /* -------------------------------------------- */ + // Define custom Entity classes + CONFIG.Actor.documentClass = RdDActor; + CONFIG.Item.documentClass = RdDItem; + CONFIG.RDD = { + resolutionTable: RdDResolutionTable.resolutionTable, + carac_array: RdDUtility.getCaracArray(), + ajustementsConditions: RdDUtility.getAjustementsConditions(), + difficultesLibres: RdDUtility.getDifficultesLibres() } - }); - /* -------------------------------------------- */ - // Define custom Entity classes - CONFIG.Actor.documentClass = RdDActor; - CONFIG.Item.documentClass = RdDItem; - CONFIG.RDD = { - resolutionTable: RdDResolutionTable.resolutionTable, - carac_array: RdDUtility.getCaracArray(), - ajustementsConditions: RdDUtility.getAjustementsConditions(), - difficultesLibres: RdDUtility.getDifficultesLibres() + /* -------------------------------------------- */ + // Register sheet application classes + Actors.unregisterSheet("core", ActorSheet); + Actors.registerSheet(SYSTEM_RDD, RdDActorSheet, { types: ["personnage"], makeDefault: true }); + Actors.registerSheet(SYSTEM_RDD, RdDActorCreatureSheet, { types: ["creature"], makeDefault: true }); + Actors.registerSheet(SYSTEM_RDD, RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true }); + Actors.registerSheet(SYSTEM_RDD, RdDActorEntiteSheet, { types: ["entite"], makeDefault: true }); + Items.unregisterSheet("core", ItemSheet); + + RdDItemSheet.register(RdDSigneDraconiqueItemSheet); + RdDItemSheet.register(RdDRencontreItemSheet); + RdDItemSheet.register(RdDConteneurItemSheet); + RdDItemSheet.register(RdDHerbeItemSheet); + RdDItemSheet.register(RdDFauneItemSheet); + RdDItemSheet.register(RdDIngredientItemSheet); + + Items.registerSheet(SYSTEM_RDD, RdDItemSheet, { + types: [ + "competence", "competencecreature", + "recettealchimique", "musique", "chant", "danse", "jeu", "recettecuisine", "oeuvre", + "objet", "arme", "armure", "livre", "potion", "munition", + "monnaie", "nourritureboisson", "gemme", + "meditation", "queue", "ombre", "souffle", "tete", "casetmr", "sort", "sortreserve", + "nombreastral", "tache", "maladie", "poison", "possession", + "tarot", "extraitpoetique" + ], makeDefault: true + }); + CONFIG.Combat.documentClass = RdDCombatManager; + + // préparation des différents modules + SystemCompendiums.init(); + DialogChronologie.init(); + ReglesOptionelles.init(); + RdDUtility.init(); + RdDDice.init(); + RdDCommands.init(); + RdDCombat.init(); + RdDCombatManager.init(); + RdDTokenHud.init(); + RdDActor.init(); + RddCompendiumOrganiser.init(); + EffetsDraconiques.init() + TMRUtility.init(); + RdDHotbar.initDropbar(); + RdDPossession.init(); + TMRRencontres.init(); + Environnement.init(); + + Hooks.once('ready', () => this.onReady()); } + async onReady() { + + /* -------------------------------------------- */ + /* Foundry VTT Initialization */ + /* -------------------------------------------- */ + // CSS patch for v9 + if (game.version) { + let sidebar = document.getElementById("sidebar"); + sidebar.style.width = "min-content"; + } + + if (Misc.isUniqueConnectedGM()) { + new Migrations().migrate(); + } + + StatusEffects.onReady(); + RdDHerbes.initializeHerbes(); + RdDDice.onReady(); + /* -------------------------------------------- */ + /* Affiche/Init le calendrier */ + let calendrier = new RdDCalendrier(); + let templatePath = "systems/foundryvtt-reve-de-dragon/templates/calendar-template.html"; + let templateData = {}; + renderTemplate(templatePath, templateData).then(html => { + calendrier.render(true); + }); + game.system.rdd.calendrier = calendrier; // Reference; + + // Avertissement si joueur sans personnage + if (!game.user.isGM && game.user.character == undefined) { + ui.notifications.info("Attention ! Vous n'êtes connecté à aucun personnage !"); + ChatMessage.create({ + content: "ATTENTION Le joueur " + game.user.name + " n'est connecté à aucun personnage !", + user: game.user.id + }); + } + if (Misc.isUniqueConnectedGM()) { + this.messageDeBienvenue(); + this.registerUsageCount(SYSTEM_RDD); + } + } + /* -------------------------------------------- */ - // Register sheet application classes - Actors.unregisterSheet("core", ActorSheet); - Actors.registerSheet(SYSTEM_RDD, RdDActorSheet, { types: ["personnage"], makeDefault: true }); - Actors.registerSheet(SYSTEM_RDD, RdDActorCreatureSheet, { types: ["creature"], makeDefault: true }); - Actors.registerSheet(SYSTEM_RDD, RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true }); - Actors.registerSheet(SYSTEM_RDD, RdDActorEntiteSheet, { types: ["entite"], makeDefault: true }); - Items.unregisterSheet("core", ItemSheet); - - RdDItemSheet.register(RdDSigneDraconiqueItemSheet); - RdDItemSheet.register(RdDRencontreItemSheet); - RdDItemSheet.register(RdDConteneurItemSheet); - RdDItemSheet.register(RdDHerbeItemSheet); - RdDItemSheet.register(RdDFauneItemSheet); - RdDItemSheet.register(RdDIngredientItemSheet); - - Items.registerSheet(SYSTEM_RDD, RdDItemSheet, { - types: [ - "competence", "competencecreature", - "recettealchimique", "musique", "chant", "danse", "jeu", "recettecuisine", "oeuvre", - "objet", "arme", "armure", "livre", "potion", "munition", - "monnaie", "nourritureboisson", "gemme", - "meditation", "queue", "ombre", "souffle", "tete", "casetmr", "sort", "sortreserve", - "nombreastral", "tache", "maladie", "poison", "possession", - "tarot", "extraitpoetique" - ], makeDefault: true - }); - CONFIG.Combat.documentClass = RdDCombatManager; - - // préparation des différents modules - SystemCompendiums.init(); - DialogChronologie.init(); - ReglesOptionelles.init(); - RdDUtility.init(); - RdDDice.init(); - RdDCommands.init(); - RdDCombat.init(); - RdDCombatManager.init(); - RdDTokenHud.init(); - RdDActor.init(); - RddCompendiumOrganiser.init(); - EffetsDraconiques.init() - TMRUtility.init(); - RdDHotbar.initDropbar(); - RdDPossession.init(); - TMRRencontres.init(); - Environnement.init(); -}); - -/* -------------------------------------------- */ -function messageDeBienvenue() { - if (game.user.isGM) { - ChatUtility.removeChatMessageContaining('
'); - ChatMessage.create({ - user: game.user.id, - content: `
Bienvenue dans le Rêve des Dragons ! + messageDeBienvenue() { + if (game.user.isGM) { + ChatUtility.removeChatMessageContaining('
'); + ChatMessage.create({ + user: game.user.id, + content: `
Bienvenue dans le Rêve des Dragons !
Vous trouverez quelques informations pour démarrer dans ce document : @Compendium[foundryvtt-reve-de-dragon.rappel-des-regles.7uGrUHGdPu0EmIu2]{Documentation MJ/Joueurs}
La commande /aide dans le chat permet de voir les commandes spécifiques à Rêve de Dragon.
` }); - } -} - -/* -------------------------------------------- */ -// Register world usage statistics -async function registerUsageCount(registerKey) { - if (game.user.isGM) { - game.settings.register("world", "world-key", { - name: "Unique world key", - scope: "world", - config: false, - default: "NONE", - type: String - }); - - let worldKey = game.settings.get("world", "world-key") - if (worldKey == undefined || worldKey == "") { - worldKey = randomID(32) - game.settings.set("world", "world-key", worldKey) } - let regURL = `https://www.uberwald.me/fvtt_appcount/count.php?name="${registerKey}"&worldKey="${worldKey}"&version="${game.release.generation}.${game.release.build}"&system="${game.system.id}"&systemversion="${game.system.version}"` - $.ajax(regURL) - /* -------------------------------------------- */ - } -} - -/* -------------------------------------------- */ -/* Foundry VTT Initialization */ -/* -------------------------------------------- */ -Hooks.once("ready", async function () { - await migrationPngWebp_1_5_34() - if (Misc.isUniqueConnectedGM()) { - new Migrations().migrate(); } - StatusEffects.onReady(); - RdDHerbes.initializeHerbes(); - RdDDice.onReady(); /* -------------------------------------------- */ - /* Affiche/Init le calendrier */ - let calendrier = new RdDCalendrier(); - let templatePath = "systems/foundryvtt-reve-de-dragon/templates/calendar-template.html"; - let templateData = {}; - renderTemplate(templatePath, templateData).then(html => { - calendrier.render(true); - }); - game.system.rdd.calendrier = calendrier; // Reference; + // Register world usage statistics + async registerUsageCount(registerKey) { + if (game.user.isGM) { + game.settings.register("world", "world-key", { + name: "Unique world key", + scope: "world", + config: false, + default: "NONE", + type: String + }); - // Avertissement si joueur sans personnage - if (!game.user.isGM && game.user.character == undefined) { - ui.notifications.info("Attention ! Vous n'êtes connecté à aucun personnage !"); - ChatMessage.create({ - content: "ATTENTION Le joueur " + game.user.name + " n'est connecté à aucun personnage !", - user: game.user.id - }); - } - if (Misc.isUniqueConnectedGM()) { - messageDeBienvenue(); - registerUsageCount(SYSTEM_RDD); - } -}); - -async function migrationPngWebp_1_5_34() { - if (!game.settings.get(SYSTEM_RDD, "migration-png-webp-1.5.34")) { - const regexOldPngJpg = /(systems\/foundryvtt-reve-de-dragon\/icons\/.*)\.(png|jpg)/; - const replaceWithWebp = '$1.webp'; - function convertImgToWebp(img) { - return img.replace(regexOldPngJpg, replaceWithWebp); - } - function prepareDocumentsImgUpdate(documents) { - return documents.filter(it => it.img && it.img.match(regexOldPngJpg)) - .map(it => { - return { _id: it.id, img: convertImgToWebp(it.img) } - }); - } - const itemsUpdates = prepareDocumentsImgUpdate(game.items); - const actorsUpdates = prepareDocumentsImgUpdate(game.actors); - //Migrate system png to webp - await Item.updateDocuments(itemsUpdates); - await Actor.updateDocuments(actorsUpdates); - game.actors.forEach(actor => { - if (actor.token?.img && actor.token.img.match(regexOldPngJpg)) { - actor.update({ "token.img": convertImgToWebp(actor.token.img) }); + let worldKey = game.settings.get("world", "world-key") + if (worldKey == undefined || worldKey == "") { + worldKey = randomID(32) + game.settings.set("world", "world-key", worldKey) } - const actorItemsToUpdate = prepareDocumentsImgUpdate(actor.items); - actor.updateEmbeddedDocuments('Item', actorItemsToUpdate); - }); - game.settings.set(SYSTEM_RDD, "migration-png-webp-1.5.34", true) - } - - // CSS patch for v9 - if (game.version) { - let sidebar = document.getElementById("sidebar"); - sidebar.style.width = "min-content"; + let regURL = `https://www.uberwald.me/fvtt_appcount/count.php?name="${registerKey}"&worldKey="${worldKey}"&version="${game.release.generation}.${game.release.build}"&system="${game.system.id}"&systemversion="${game.system.version}"` + $.ajax(regURL) + /* -------------------------------------------- */ + } } } -/* -------------------------------------------- */ -/* Dice-so-nice ready */ -/* -------------------------------------------- */ -Hooks.once('diceSoNiceReady', (dice3d) => RdDDice.diceSoNiceReady(dice3d)); +SystemReveDeDragon.start();