diff --git a/module/actor-sheet.js b/module/actor-sheet.js index 6b103ad2..075c6d22 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -25,7 +25,7 @@ export class RdDActorSheet extends ActorSheet { return mergeObject(super.defaultOptions, { classes: ["rdd", "sheet", "actor"], template: "systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html", - width: 640, + width: 550, tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }], dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }], showCompNiveauBase: false, @@ -36,6 +36,7 @@ export class RdDActorSheet extends ActorSheet { /* -------------------------------------------- */ async getData() { this.timerRecherche = undefined; + this.actor.computeEtatGeneral(); let formData = { title: this.title, diff --git a/module/actor-vehicule-sheet.js b/module/actor-vehicule-sheet.js index 2729f2af..5803f3f7 100644 --- a/module/actor-vehicule-sheet.js +++ b/module/actor-vehicule-sheet.js @@ -18,5 +18,22 @@ export class RdDActorVehiculeSheet extends RdDActorSheet { }); } + activateListeners(html) { + super.activateListeners(html); + if (!this.options.editable) return; + + html.find('.resistance-moins').click(async event => { + this.actor.vehicleIncDec("resistance", -1); + }); + html.find('.resistance-plus').click(async event => { + this.actor.vehicleIncDec("resistance", 1); + }); + html.find('.structure-moins').click(async event => { + this.actor.vehicleIncDec("structure", -1); + }); + html.find('.structure-plus').click(async event => { + this.actor.vehicleIncDec("structure", 1); + }); + } } diff --git a/module/actor.js b/module/actor.js index c6c2841b..2a975124 100644 --- a/module/actor.js +++ b/module/actor.js @@ -147,10 +147,12 @@ export class RdDActor extends Actor { if (this.isPersonnage()) this._prepareCharacterData(this) if (this.isCreature()) this._prepareCreatureData(this) if (this.isVehicule()) this._prepareVehiculeData(this) + this.computeEtatGeneral(); } /* -------------------------------------------- */ setRollWindowsOpened(flag) { + // TODO: résoudre le souci lié aux ids dans les fenêtres roll this.rollWindowsOpened = flag; } @@ -162,7 +164,6 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ _prepareCreatureData(actorData) { this.computeEncombrementTotalEtMalusArmure(); - this.computeEtatGeneral(); } /* -------------------------------------------- */ @@ -180,7 +181,6 @@ export class RdDActor extends Actor { this.computeIsHautRevant(); await this.cleanupConteneurs(); await this.computeEncombrementTotalEtMalusArmure(); - this.computeEtatGeneral(); } /* -------------------------------------------- */ @@ -770,7 +770,7 @@ export class RdDActor extends Actor { actor: this, competence: duplicate(this.getDraconicOuPossession()), canClose: false, - rencontre: await game.system.rencontresTMR.getReveDeDragon(force), + rencontre: await game.system.rdd.rencontresTMR.getReveDeDragon(force), tmr: true, use: { libre: false, conditions: false }, forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: this.getReveActuel() } } @@ -1359,10 +1359,10 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ computePrixTotalEquipement() { - const deniers = this.items.filter(it => it.isEquipement()) - .map(it => it.prixTotalDeniers()) + const valeur = this.items.filter(it => it.isEquipement()) + .map(it => it.valeurTotale()) .reduce(Misc.sum(), 0); - return deniers / 100; + return valeur / 100; } /* -------------------------------------------- */ @@ -1400,21 +1400,22 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ computeEtatGeneral() { // Pas d'état général pour les entités forçage à 0 + if (this.type == 'vehicule') { + return + } if (this.type == 'entite') { this.system.compteurs.etat.value = 0; return } // Pour les autres - let sante = this.system.sante - let compteurs = this.system.compteurs - let state = Math.min(sante.vie.value - sante.vie.max, 0); - if (ReglesOptionelles.isUsing("appliquer-fatigue") && sante.fatigue) { - state += RdDUtility.currentFatigueMalus(sante.fatigue.value, sante.endurance.max); + let state = Math.min(this.system.sante.vie.value - this.system.sante.vie.max, 0); + if (ReglesOptionelles.isUsing("appliquer-fatigue") && this.system.sante.fatigue) { + state += RdDUtility.currentFatigueMalus(this.system.sante.fatigue.value, this.system.sante.endurance.max); } // Ajout de l'éthylisme - state += Math.min(0, (compteurs.ethylisme?.value ?? 0)); + state += Math.min(0, (this.system.compteurs.ethylisme?.value ?? 0)); - compteurs.etat.value = state; + this.system.compteurs.etat.value = state; } /* -------------------------------------------- */ @@ -1778,6 +1779,18 @@ export class RdDActor extends Actor { } return result; } + + async vehicleIncDec(name, inc) { + if (!this.isVehicule() || !['resistance', 'structure'].includes(name)) { + return + } + const value = this.system.etat[name].value; + const max = this.system.etat[name].max; + const newValue = value + inc; + if (0 <= newValue && newValue <=max) { + await this.update({ [`system.etat.${name}.value`]: newValue }) + } + } isDead() { return !this.isEntite() && this.system.sante.vie.value < -this.getSConst() @@ -3267,10 +3280,9 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async equiperObjet(itemID) { let item = this.getEmbeddedDocument('Item', itemID); - if (item?.system) { + if (item && ['arme', 'armure'].includes(item.type)) { const isEquipe = !item.system.equipe; - let update = { _id: item.id, "system.equipe": isEquipe }; - await this.updateEmbeddedDocuments('Item', [update]); + await this.updateEmbeddedDocuments('Item', [{ _id: item.id, "system.equipe": isEquipe }]); this.computeEncombrementTotalEtMalusArmure(); // Mise à jour encombrement if (isEquipe) this.verifierForceMin(item); @@ -3377,8 +3389,6 @@ export class RdDActor extends Actor { : await this.santeIncDec("vie", -encaissement.vie); const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance, encaissement.critiques > 0); - this.computeEtatGeneral(); - mergeObject(encaissement, { alias: this.name, hasPlayerOwner: this.hasPlayerOwner, @@ -3571,41 +3581,25 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ getFortune() { return this.itemTypes['monnaie'] - .map(m => Number(m.system.valeur_deniers) * Number(m.system.quantite)) + .map(m => Number(m.system.cout) * Number(m.system.quantite)) .reduce(Misc.sum(), 0); } /* -------------------------------------------- */ - async depenserDeniers(depense, dataObj = undefined, quantite = 1, toActorId) { + async payerSols(depense) { depense = Number(depense); - let fortune = this.getFortune(); - console.log("depenserDeniers", game.user.character, depense, fortune); - let msg = ""; if (depense == 0) { - if (dataObj) { - dataObj.payload.system.cout = depense / 100; // Mise à jour du prix en sols , avec le prix acheté - dataObj.payload.system.quantite = quantite; - await this.createEmbeddedDocuments('Item', [dataObj.payload]); - msg += `
L'objet ${dataObj.payload.name} a été ajouté gratuitement à votre inventaire.`; - } + return; } - else { - if (fortune >= depense) { - const toActor = game.actors.get(toActorId) - await toActor?.ajouterDeniers(depense, this.id); - await Monnaie.optimiser(this, fortune - depense); - msg = `Vous avez payé ${depense} Deniers${toActor ? " à " + toActor.name : ''}, qui ont été soustraits de votre argent.`; - RdDAudio.PlayContextAudio("argent"); // Petit son - - if (dataObj) { - dataObj.payload.system.cout = depense / 100; // Mise à jour du prix en sols , avec le prix acheté - dataObj.payload.system.quantite = quantite; - await this.createEmbeddedDocuments('Item', [dataObj.payload]); - msg += `
Et l'objet ${dataObj.payload.name} a été ajouté à votre inventaire.`; - } - } else { - msg = "Vous n'avez pas assez d'argent pour payer cette somme !"; - } + let fortune = this.getFortune(); + console.log("payer", game.user.character, depense, fortune); + let msg = ""; + if (fortune >= depense) { + await Monnaie.optimiserFortune(this, fortune - depense); + msg = `Vous avez payé ${depense} Sols, qui ont été soustraits de votre argent.`; + RdDAudio.PlayContextAudio("argent"); // Petit son + } else { + msg = "Vous n'avez pas assez d'argent pour payer cette somme !"; } let message = { @@ -3615,38 +3609,38 @@ export class RdDActor extends Actor { ChatMessage.create(message); } - async depenser(depense) { - let reste = this.getFortune() - Number.parseInt(depense); + async depenserSols(sols) { + let reste = this.getFortune() - Number(sols); if (reste >= 0) { - await Monnaie.optimiser(this, reste); + await Monnaie.optimiserFortune(this, reste); } return reste; } - async ajouterDeniers(gain, fromActorId = undefined) { - gain = Number.parseInt(gain); - if (gain < 0) { - ui.notifications.error(`Impossible d'ajouter un gain de ${gain} <0`); + async ajouterSols(sols, fromActorId = undefined) { + sols = Number(sols); + if (sols == 0) { return; } - if (gain == 0) { + if (sols < 0) { + ui.notifications.error(`Impossible d'ajouter un gain de ${sols} <0`); return; } if (fromActorId && !game.user.isGM) { RdDActor.remoteActorCall({ userId: Misc.connectedGMOrUser(), actorId: this.id, - method: 'ajouterDeniers', args: [gain, fromActorId] + method: 'ajouterSols', args: [sols, fromActorId] }); } else { const fromActor = game.actors.get(fromActorId) - await Monnaie.optimiser(this, gain + this.getFortune()); + await Monnaie.optimiserFortune(this, sols + this.getFortune()); RdDAudio.PlayContextAudio("argent"); // Petit son ChatMessage.create({ whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), - content: `Vous avez reçu ${gain} Deniers ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.` + content: `Vous avez reçu ${sols} Sols ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.` }); } } @@ -3680,23 +3674,23 @@ export class RdDActor extends Actor { const itemId = vente.item._id; const isItemEmpilable = "quantite" in vente.item.system; - const coutDeniers = Math.floor((achat.prixTotal ?? 0) * 100); + const cout = Number(achat.prixTotal ?? 0); achat.quantiteTotal = (achat.choix.nombreLots ?? 1) * (vente.tailleLot); if (acheteur) { - let resteAcheteur = await acheteur.depenser(coutDeniers); + let resteAcheteur = await acheteur.depenserSols(cout); if (resteAcheteur < 0) { - ChatUtility.notifyUser(achat.userId, 'warn', `Vous n'avez pas assez d'argent pour payer ${Math.ceil(coutDeniers / 100)} sols !`); + ChatUtility.notifyUser(achat.userId, 'warn', `Vous n'avez pas assez d'argent pour payer ${Math.ceil(cout / 100)} sols !`); return; } } const itemVendu = vendeur?.getObjet(itemId); if (itemVendu) { if (isItemEmpilable ? (itemVendu.system.quantite < achat.quantiteTotal) : (achat.choix.nombreLots != 1)) { - await acheteur?.ajouterDeniers(coutDeniers); + await acheteur?.ajouterSols(cout); ChatUtility.notifyUser(achat.userId, 'warn', `Le vendeur n'a plus assez de ${vente.item.name} !`); return; } - vendeur.ajouterDeniers(coutDeniers); + vendeur.ajouterSols(cout); let resteQuantite = (itemVendu.system.quantite ?? 1) - achat.quantiteTotal; if (resteQuantite == 0) { vendeur.deleteEmbeddedDocuments("Item", [itemId]) @@ -3719,7 +3713,7 @@ export class RdDActor extends Actor { await acheteur.consommerNourritureboisson(items[0].id, achat.choix, vente.actingUserId); } } - if (coutDeniers > 0) { + if (cout > 0) { RdDAudio.PlayContextAudio("argent"); } const chatAchatItem = duplicate(vente); diff --git a/module/dialog-item-achat.js b/module/dialog-item-achat.js index b137b5ab..649b1545 100644 --- a/module/dialog-item-achat.js +++ b/module/dialog-item-achat.js @@ -1,6 +1,5 @@ import { Monnaie } from "./item-monnaie.js"; -import { Misc } from "./misc.js"; import { RdDUtility } from "./rdd-utility.js"; export class DialogItemAchat extends Dialog { @@ -19,7 +18,7 @@ export class DialogItemAchat extends Dialog { return undefined; } - const prixLot = Monnaie.arrondiDeniers(button.attributes['data-prixLot']?.value ?? 0); + const prixLot = Number(button.attributes['data-prixLot']?.value ?? 0); return { item: json ? JSON.parse(json) : undefined, actingUserId: game.user.id, diff --git a/module/dialog-item-vente.js b/module/dialog-item-vente.js index 8669e365..32639eef 100644 --- a/module/dialog-item-vente.js +++ b/module/dialog-item-vente.js @@ -1,5 +1,4 @@ import { HtmlUtility } from "./html-utility.js"; -import { Misc } from "./misc.js"; export class DialogItemVente extends Dialog { diff --git a/module/environnement.js b/module/environnement.js new file mode 100644 index 00000000..38b8c554 --- /dev/null +++ b/module/environnement.js @@ -0,0 +1,210 @@ +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' +] + +export class Environnement { + + static init() { + game.settings.register(SYSTEM_RDD, SETTINGS_LISTE_MILIEUX, { + name: "Liste des milieux proposés", + hint: "Liste des milieux proposés pour la faune&flore, 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', ITEM_ENVIRONNEMENT_TYPES, `ressources en "${search}"`); + return true + } + + async getRandom(search) { + const table = await this.buildEnvironnementTable(search); + return await CompendiumTableHelpers.getRandom(table, 'Item', ITEM_ENVIRONNEMENT_TYPES, undefined, `ressources en "${search}"`); + } + + 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; + return await this.table.buildTable(itemFrequenceEnMilieu, isPresentEnMilieu); + } + + + async getElements(itemFrequence, filter) { + return await this.table.getContent(itemFrequence, filter); + } +} + +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/item-monnaie.js b/module/item-monnaie.js index 2d48004a..7a16c258 100644 --- a/module/item-monnaie.js +++ b/module/item-monnaie.js @@ -4,22 +4,22 @@ import { LOG_HEAD } from "./constants.js"; const MONNAIE_ETAIN = { name: "Etain (1 denier)", type: 'monnaie', img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp", - system: { quantite: 0, valeur_deniers: 1, encombrement: 0.001, description: "" } + system: { quantite: 0, cout: 0.01, encombrement: 0.001, description: "" } }; const MONNAIE_BRONZE = { name: "Bronze (10 deniers)", type: 'monnaie', img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_bronze_epees.webp", - system: { quantite: 0, valeur_deniers: 10, encombrement: 0.002, description: "" } + system: { quantite: 0, cout: 0.10, encombrement: 0.002, description: "" } }; const MONNAIE_ARGENT = { name: "Argent (1 sol)", type: 'monnaie', img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_argent_sol.webp", - system: { quantite: 0, valeur_deniers: 100, encombrement: 0.003, description: "" } + system: { quantite: 0, cout: 1, encombrement: 0.003, description: "" } }; const MONNAIE_OR = { name: "Or (10 sols)", type: 'monnaie', img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_or_sol.webp", - system: { quantite: 0, valeur_deniers: 1000, encombrement: 0.004, description: "" } + system: { quantite: 0, cout: 10, encombrement: 0.004, description: "" } }; const MONNAIES_STANDARD = [MONNAIE_ETAIN, MONNAIE_BRONZE, MONNAIE_ARGENT, MONNAIE_OR]; @@ -32,7 +32,7 @@ export class Monnaie { static monnaiesManquantes(actor) { const disponibles = actor.itemTypes['monnaie']; - const manquantes = MONNAIES_STANDARD.filter(standard => !disponibles.find(disponible => Monnaie.deValeur(disponible, standard.system?.valeur_deniers))); + const manquantes = MONNAIES_STANDARD.filter(standard => !disponibles.find(disponible => Monnaie.deValeur(disponible, standard.system?.cout))); if (manquantes.length > 0) { console.error(`${LOG_HEAD} monnaiesManquantes pour ${actor.name}`, manquantes, ' avec monnaies', disponibles, MONNAIES_STANDARD); } @@ -40,15 +40,15 @@ export class Monnaie { } static deValeur(monnaie, valeur) { - return valeur == monnaie.system.valeur_deniers + return Monnaie.valEntiere(valeur) == Monnaie.valEntiere(monnaie.system.cout) } - static arrondiDeniers(sols) { - return Number(sols).toFixed(2); + static valEntiere(sols) { + return Math.max(Math.floor((sols??0)*100), 0); } - static triValeurDenier() { - return Misc.ascending(item => item.system.valeur_deniers) + static triValeurEntiere() { + return Misc.ascending(item => Monnaie.valEntiere(item.system.cout)) } static async creerMonnaiesStandard(actor) { @@ -65,28 +65,28 @@ export class Monnaie { return deniers; } - static async optimiser(actor, fortune) { - let reste = fortune; + static async optimiserFortune(actor, fortune) { + let resteEnDeniers = Math.round(fortune*100); let monnaies = actor.itemTypes['monnaie']; let updates = []; - let parValeur = Misc.classifyFirst(monnaies, it => it.system.valeur_deniers); - for (let valeur of [1000, 100, 10, 1]) { - const itemPiece = parValeur[valeur]; + let parValeur = Misc.classifyFirst(monnaies, it => Monnaie.valEntiere(it.system.cout)); + for (let valeurDeniers of [1000, 100, 10, 1]) { + const itemPiece = parValeur[valeurDeniers]; if (itemPiece) { - const quantite = Math.floor(reste / valeur); + const quantite = Math.floor(resteEnDeniers / valeurDeniers); if (quantite != itemPiece.system.quantite) { - updates.push({ _id: parValeur[valeur].id, 'system.quantite': quantite }); + updates.push({ _id: parValeur[valeurDeniers].id, 'system.quantite': quantite }); } - reste -= quantite*valeur; + resteEnDeniers -= quantite*valeurDeniers; } } - console.log('Monnaie.optimiser', actor.name, 'total', fortune, 'parValeur', parValeur, 'updates', updates, 'reste', reste); + console.log('Monnaie.optimiserFortune', actor.name, 'total', fortune, 'parValeur', parValeur, 'updates', updates, 'reste', resteEnDeniers); if (updates.length > 0) { await actor.updateEmbeddedDocuments('Item', updates); } - if (reste > 0){ + if (resteEnDeniers > 0){ // créer le reste en deniers fortune en deniers - await Monnaie.creerMonnaiesDeniers(actor, reste); + await Monnaie.creerMonnaiesDeniers(actor, resteEnDeniers); } } diff --git a/module/item.js b/module/item.js index 29fb3281..fd41209b 100644 --- a/module/item.js +++ b/module/item.js @@ -1,5 +1,6 @@ import { DialogItemVente } from "./dialog-item-vente.js"; import { Grammar } from "./grammar.js"; +import { Monnaie } from "./item-monnaie.js"; import { RdDHerbes } from "./rdd-herbes.js"; import { RdDUtility } from "./rdd-utility.js"; @@ -69,6 +70,30 @@ export class RdDItem extends Item { return defaultItemImg[itemType]; } + static isEquipementFieldEditable(type, field) { + switch (field) { + case 'quantite': + if (['conteneur'].includes(type)) { + return false; + } + break; + case 'cout': + if(['monnaie'].includes(type)){ + return game.user.isGM; + } + break; + } + return true; + } + + static getUniteQuantite(type) { + switch (type) { + case "monnaie": return "(Pièces)" + case "herbe": return "(Brins)" + case "ingredient": return "(Pépins ou Brins)" + } + return ''; + } constructor(itemData, context) { if (!itemData.img) { @@ -167,12 +192,12 @@ export class RdDItem extends Item { return Math.max(this.system.encombrement ?? 0, 0); } - prixTotalDeniers() { - return this.getQuantite() * this.valeurDeniers() + valeurTotale() { + return this.getQuantite() * this.valeur() } - valeurDeniers() { - return Math.max(Math.round(this.system.cout ? (this.system.cout * 100) : (this.system.valeur_deniers ?? 0)), 0) + valeur() { + return this.system.cout ?? 0 } prepareDerivedData() { @@ -494,7 +519,7 @@ export class RdDItem extends Item { /* -------------------------------------------- */ _monnaieChatData() { return [ - `Valeur en Deniers: ${this.system.valeur_deniers}`, + `Valeur en Sols: ${this.system.cout}`, `Encombrement: ${this.system.encombrement}` ] } @@ -564,5 +589,4 @@ export class RdDItem extends Item { ] } - } diff --git a/module/migrations.js b/module/migrations.js index 886dfd5d..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"; } @@ -195,7 +196,8 @@ class _10_2_10_DesirLancinant_IdeeFixe extends Migration { categorie = 'ideefixe'; name = it.name.replace('Idée fixe : ', '') } - return { _id: it.id, name: name, + return { + _id: it.id, name: name, 'system.ideefixe': undefined, 'system.lancinant': undefined, 'system.categorie': categorie @@ -206,8 +208,54 @@ class _10_2_10_DesirLancinant_IdeeFixe extends Migration { await this.applyItemsUpdates(items => items .filter(it => ['queue', 'ombre'].includes(it.type)) .map(it => this.migrateQueue(it)) - //.filter(it => it.system.categorie ) - ); + ); + } +} + +class _10_3_0_Inventaire extends Migration { + get code() { return "migration-equipement-inventaire"; } + get version() { return "10.3.0"; } + + async migrate() { + await this.applyItemsUpdates(items => { + return this._updatesMonnaies(items) + .concat(this._updatesNonEquipe(items)) + .concat(this._updatesObjets(items)) + }); + } + + _updatesNonEquipe(items) { + return items + .filter(it => ['munition'].includes(it.type)) + .map(it => { return { _id: it.id, 'system.equipe': undefined } }); + } + _updatesObjets(items) { + return items + .filter(it => ['objet'].includes(it.type)) + .map(it => { return { _id: it.id, 'system.resistance': undefined, 'system.equipe': undefined } }); + } + _updatesMonnaies(items) { + return items + .filter(it => ['monnaie'].includes(it.type) && it.system.cout == undefined) + .map(it => { return { _id: it.id, 'system.cout': it.system.valeur_deniers / 100, 'system.valeur_deniers': undefined } }); + } +} + +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') }] + } } } @@ -220,6 +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_FrequenceEnvironnement() ]; } @@ -234,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/misc.js b/module/misc.js index e016508c..fb506356 100644 --- a/module/misc.js +++ b/module/misc.js @@ -24,7 +24,7 @@ export class Misc { } static sum() { - return (a, b) => a + b; + return (a, b) => Number(a) + Number(b); } static ascending(orderFunction = x => x) { @@ -41,6 +41,10 @@ export class Misc { return 0; } + static typeName(type, subType) { + return game.i18n.localize(`${type.toUpperCase()}.Type${Misc.upperFirst(subType)}`); + } + /** * Converts the value to an integer, or to 0 if undefined/null/not representing integer * @param {*} value value to convert to an integer using parseInt @@ -102,7 +106,11 @@ export class Misc { } static join(params, separator = '') { - return params?.reduce((a, b) => a + separator + b) ?? ''; + return params?.reduce(Misc.joining(separator)) ?? ''; + } + + static joining(separator = '') { + return (a, b) => a + separator + b; } static connectedGMOrUser(ownerId = undefined) { diff --git a/module/rdd-commands.js b/module/rdd-commands.js index 9f4b4bbb..f567dcfb 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)?/; @@ -21,74 +22,87 @@ const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/; export class RdDCommands { static init() { - if (!game.system.rdd.commands) { - const rddCommands = new RdDCommands(); - rddCommands.registerCommand({ path: ["/aide"], func: (content, msg, params) => rddCommands.help(msg), descr: "Affiche l'aide pour toutes les commandes" }); - rddCommands.registerCommand({ path: ["/help"], func: (content, msg, params) => rddCommands.help(msg), descr: "Affiche l'aide pour toutes les commandes" }); + game.system.rdd.commands = new RdDCommands(); + } - rddCommands.registerCommand({ path: ["/liste", "comp"], func: (content, msg, params) => RdDRollTables.getCompetence('liste'), descr: "Affiche la liste des compétences" }); + constructor() { + this.commandsTable = undefined; + } - rddCommands.registerCommand({ path: ["/table", "queue"], func: (content, msg, params) => RdDRollTables.getQueue('liste'), descr: "Affiche la table des Queues de Dragon" }); - rddCommands.registerCommand({ path: ["/table", "ombre"], func: (content, msg, params) => RdDRollTables.getOmbre('liste'), descr: "Affiche la table des Ombres de Thanatos" }); - rddCommands.registerCommand({ path: ["/table", "tetehr"], func: (content, msg, params) => RdDRollTables.getTeteHR('liste'), descr: "Affiche la table des Têtes de Dragon pour Hauts Revants" }); - rddCommands.registerCommand({ path: ["/table", "tete"], func: (content, msg, params) => RdDRollTables.getTete('liste'), descr: "Affiche la table des Tête de Dragon pour tous" }); - rddCommands.registerCommand({ path: ["/table", "souffle"], func: (content, msg, params) => RdDRollTables.getSouffle('liste'), descr: "Affiche la table des Souffles de Dragon" }); - rddCommands.registerCommand({ path: ["/table", "tarot"], func: (content, msg, params) => RdDRollTables.getTarot('liste'), descr: "Affiche la table les cartes du Tarot Draconique" }); - rddCommands.registerCommand({ path: ["/table", "ideefixe"], func: (content, msg, params) => RdDRollTables.getIdeeFixe('liste'), descr: "Affiche la table des Idées fixes" }); - rddCommands.registerCommand({ path: ["/table", "desir"], func: (content, msg, params) => RdDRollTables.getDesirLancinant('liste'), descr: "Affiche la table des Désirs Lancinants" }); - rddCommands.registerCommand({ - path: ["/table", "rencontre"], func: (content, msg, params) => rddCommands.tableRencontres(msg, params), - descr: `Affiche la table des Rencontres + _registerCommands() { + this.commandsTable = {} + this.registerCommand({ path: ["/aide"], func: (content, msg, params) => this.help(msg), descr: "Affiche l'aide pour toutes les commandes" }); + this.registerCommand({ path: ["/help"], func: (content, msg, params) => this.help(msg), descr: "Affiche l'aide pour toutes les commandes" }); + + this.registerCommand({ path: ["/liste", "comp"], func: (content, msg, params) => RdDRollTables.getCompetence('liste'), descr: "Affiche la liste des compétences" }); + + this.registerCommand({ path: ["/table", "queue"], func: (content, msg, params) => RdDRollTables.getQueue('liste'), descr: "Affiche la table des Queues de Dragon" }); + this.registerCommand({ path: ["/table", "ombre"], func: (content, msg, params) => RdDRollTables.getOmbre('liste'), descr: "Affiche la table des Ombres de Thanatos" }); + this.registerCommand({ path: ["/table", "tetehr"], func: (content, msg, params) => RdDRollTables.getTeteHR('liste'), descr: "Affiche la table des Têtes de Dragon pour Hauts Revants" }); + this.registerCommand({ path: ["/table", "tete"], func: (content, msg, params) => RdDRollTables.getTete('liste'), descr: "Affiche la table des Tête de Dragon pour tous" }); + this.registerCommand({ path: ["/table", "souffle"], func: (content, msg, params) => RdDRollTables.getSouffle('liste'), descr: "Affiche la table des Souffles de Dragon" }); + this.registerCommand({ path: ["/table", "tarot"], func: (content, msg, params) => RdDRollTables.getTarot('liste'), descr: "Affiche la table les cartes du Tarot Draconique" }); + this.registerCommand({ path: ["/table", "ideefixe"], func: (content, msg, params) => RdDRollTables.getIdeeFixe('liste'), descr: "Affiche la table des Idées fixes" }); + this.registerCommand({ path: ["/table", "desir"], func: (content, msg, params) => RdDRollTables.getDesirLancinant('liste'), descr: "Affiche la table des Désirs Lancinants" }); + this.registerCommand({ + path: ["/table", "rencontre"], func: (content, msg, params) => this.tableRencontres(msg, params), + descr: `Affiche la table des Rencontres
/table rencontre deso affiche la table des rencontres en Désolation -
/table rencontre mauvaise affiche la table des mauvaises rencontres` }); +
/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 ressource naturelles pour 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" }); + this.registerCommand({ path: ["/tirer", "tetehr"], func: (content, msg, params) => RdDRollTables.getTeteHR('chat'), descr: "Tire une Tête de Dragon pour Hauts Revants" }); + this.registerCommand({ path: ["/tirer", "tete"], func: (content, msg, params) => RdDRollTables.getTete('chat'), descr: "Tire une Tête de Dragon" }); + this.registerCommand({ path: ["/tirer", "souffle"], func: (content, msg, params) => RdDRollTables.getSouffle('chat'), descr: "Tire un Souffle de Dragon" }); + this.registerCommand({ path: ["/tirer", "tarot"], func: (content, msg, params) => RdDRollTables.getTarot('chat'), descr: "Tire une carte du Tarot Draconique" }); + this.registerCommand({ path: ["/tirer", "ideefixe"], func: (content, msg, params) => RdDRollTables.getIdeeFixe('chat'), descr: "Tire une Idée fixe" }); + this.registerCommand({ path: ["/tirer", "desir"], func: (content, msg, params) => RdDRollTables.getDesirLancinant('chat'), descr: "Tire un Désir Lancinant" }); + this.registerCommand({ path: ["/tirer", "rencontre"], func: (content, msg, params) => this.getRencontreTMR(params), descr: `Détermine une rencontre dans les TMR (synonyme de "/tmrr")` }); + this.registerCommand({ path: ["/tirer", "milieu"], func: (content, msg, params) => this.tableMilieu(msg, params, 'chat'), descr: "Effectue un tirage dans la table desressource naturelles pour un milieu donné" }); + + this.registerCommand({ path: ["/meteo"], func: (content, msg, params) => this.getMeteo(msg, params), descr: "Propose une météo marine" }); + this.registerCommand({ path: ["/nom"], func: (content, msg, params) => RdDNameGen.getName(msg, params), descr: "Génère un nom aléatoire" }); - rddCommands.registerCommand({ path: ["/tirer", "comp"], func: (content, msg, params) => RdDRollTables.getCompetence('chat'), descr: "Tire une compétence au hasard" }); - rddCommands.registerCommand({ path: ["/tirer", "queue"], func: (content, msg, params) => RdDRollTables.getQueue('chat'), descr: "Tire une Queue de Dragon" }); - rddCommands.registerCommand({ path: ["/tirer", "ombre"], func: (content, msg, params) => RdDRollTables.getOmbre('chat'), descr: "Tire une Ombre de Thanatos" }); - rddCommands.registerCommand({ path: ["/tirer", "tetehr"], func: (content, msg, params) => RdDRollTables.getTeteHR('chat'), descr: "Tire une Tête de Dragon pour Hauts Revants" }); - rddCommands.registerCommand({ path: ["/tirer", "tete"], func: (content, msg, params) => RdDRollTables.getTete('chat'), descr: "Tire une Tête de Dragon" }); - rddCommands.registerCommand({ path: ["/tirer", "souffle"], func: (content, msg, params) => RdDRollTables.getSouffle('chat'), descr: "Tire un Souffle de Dragon" }); - rddCommands.registerCommand({ path: ["/tirer", "tarot"], func: (content, msg, params) => RdDRollTables.getTarot('chat'), descr: "Tire une carte du Tarot Draconique" }); - rddCommands.registerCommand({ path: ["/tirer", "ideefixe"], func: (content, msg, params) => RdDRollTables.getIdeeFixe('chat'), descr: "Tire une Idée fixe" }); - rddCommands.registerCommand({ path: ["/tirer", "desir"], func: (content, msg, params) => RdDRollTables.getDesirLancinant('chat'), descr: "Tire un Désir Lancinant" }); - rddCommands.registerCommand({ path: ["/tirer", "rencontre"], func: (content, msg, params) => rddCommands.getRencontreTMR(params), descr: `Détermine une rencontre dans les TMR (synonyme de "/tmrr")` }); - - rddCommands.registerCommand({ path: ["/meteo"], func: (content, msg, params) => rddCommands.getMeteo(msg, params), descr: "Propose une météo marine" }); - rddCommands.registerCommand({ path: ["/nom"], func: (content, msg, params) => RdDNameGen.getName(msg, params), descr: "Génère un nom aléatoire" }); - - rddCommands.registerCommand({ - path: ["/tmr"], func: (content, msg, params) => rddCommands.findTMR(msg, params), - descr: `Cherche où se trouve une case des Terres médianes + this.registerCommand({ + path: ["/tmr"], func: (content, msg, params) => this.findTMR(msg, params), + descr: `Cherche où se trouve une case des Terres médianes
/tmr sord indique que la cité Sordide est en D13 -
/tmr foret donne la liste des TMR dont le nom contient "foret" (donc, toutes les forêts)` }); - rddCommands.registerCommand({ - path: ["/tmra"], func: (content, msg, params) => rddCommands.getTMRAleatoire(msg, params), - descr: `Tire une case aléatoire des Terres médianes +
/tmr foret donne la liste des TMR dont le nom contient "foret" (donc, toutes les forêts)` + }); + this.registerCommand({ + path: ["/tmra"], func: (content, msg, params) => this.getTMRAleatoire(msg, params), + descr: `Tire une case aléatoire des Terres médianes
/tmra forêt détermine une 'forêt' aléatoire -
/tmra détermine une case aléatoire dans toutes les TMR` }); - rddCommands.registerCommand({ - path: ["/tmrr"], func: (content, msg, params) => rddCommands.getRencontreTMR(params), - descr: `Détermine une rencontre dans les TMR +
/tmra détermine une case aléatoire dans toutes les TMR` + }); + this.registerCommand({ + path: ["/tmrr"], func: (content, msg, params) => this.getRencontreTMR(params), + descr: `Détermine une rencontre dans les TMR
/tmrr forêt détermine une rencontre aléatoire en 'forêt'
/tmrr mauvaise détermine une mauvaise rencontre aléatoire -
/tmrr for 47 détermine la rencontre en 'forêt' pour un jet de dé de 47` }); +
/tmrr for 47 détermine la rencontre en 'forêt' pour un jet de dé de 47` + }); - rddCommands.registerCommand({ - path: ["/xp", "comp"], func: (content, msg, params) => rddCommands.getCoutXpComp(msg, params), - descr: `Détermine le coût d'expérience pour augmenter une compétence. Exemples: + this.registerCommand({ + path: ["/xp", "comp"], func: (content, msg, params) => this.getCoutXpComp(msg, params), + descr: `Détermine le coût d'expérience pour augmenter une compétence. Exemples:
/xp comp -6 1: pour passer de -6 à +1
/xp comp +4: pour atteindre le niveau 4 (depuis +3)` - }); + }); - rddCommands.registerCommand({ - path: ["/xp", "carac"], func: (content, msg, params) => rddCommands.getCoutXpCarac(msg, params), - descr: `Détermine le coût d'expérience pour augmenter une caractéristique. Exemples: + this.registerCommand({ + path: ["/xp", "carac"], func: (content, msg, params) => this.getCoutXpCarac(msg, params), + descr: `Détermine le coût d'expérience pour augmenter une caractéristique. Exemples:
/xp carac 15: coût pour atteindre 15 (depuis 14)` - }); + }); - rddCommands.registerCommand({ - path: ["/rdd"], func: (content, msg, params) => rddCommands.rollRdd(msg, params), - descr: `Effectue un jet de dés dans la table de résolution. Exemples: + this.registerCommand({ + path: ["/rdd"], func: (content, msg, params) => this.rollRdd(msg, params), + descr: `Effectue un jet de dés dans la table de résolution. Exemples:
/rdd ouvre la table de résolution
/rdd 10 3 effectue un jet 10 à +3
/rdd 15 -2 effectue un jet 15 à -2 @@ -96,57 +110,58 @@ export class RdDCommands {
/rdd Vue Vigilance -2 effectue un jet de Vue/Vigilance à -2 pour les tokens sélectionnés
/rdd vol déser +2 effectue un jet de Volonté/Survie en désert à +2 pour les tokens sélectionnés ` - }); - rddCommands.registerCommand({ path: ["/ddr"], func: (content, msg, params) => rddCommands.rollDeDraconique(msg), descr: "Lance un Dé Draconique" }); + }); + this.registerCommand({ path: ["/ddr"], func: (content, msg, params) => this.rollDeDraconique(msg), descr: "Lance un Dé Draconique" }); - rddCommands.registerCommand({ - path: ["/payer"], func: (content, msg, params) => RdDUtility.afficherDemandePayer(params[0], params[1]), - descr: `Demande aux joueurs de payer un montant. Exemples: + this.registerCommand({ + path: ["/payer"], func: (content, msg, params) => RdDUtility.afficherDemandePayer(params[0], params[1]), + descr: `Demande aux joueurs de payer un montant. Exemples:
/payer 5s 10d permet d'envoyer un message pour payer 5 sols et 10 deniers
/payer 10d permet d'envoyer un message pour payer 10 deniers` - }); - rddCommands.registerCommand({ - path: ["/astro"], func: (content, msg, params) => RdDUtility.afficherHeuresChanceMalchance(Misc.join(params, ' ')), - descr: `Affiche les heures de chance et de malchance selon l'heure de naissance donnée en argument. Exemples pour l'heure de la Lyre: + }); + this.registerCommand({ + path: ["/astro"], func: (content, msg, params) => RdDUtility.afficherHeuresChanceMalchance(Misc.join(params, ' ')), + descr: `Affiche les heures de chance et de malchance selon l'heure de naissance donnée en argument. Exemples pour l'heure de la Lyre:
/astro 7
/astro Lyre
/astro Lyr` - }); + }); - rddCommands.registerCommand({ - path: ["/signe", "+"], func: (content, msg, params) => rddCommands.creerSignesDraconiques(), - descr: "Crée un signe draconique et l'ajoute aux haut-rêvants choisis." - }); + this.registerCommand({ + path: ["/signe", "+"], func: (content, msg, params) => this.creerSignesDraconiques(), + descr: "Crée un signe draconique et l'ajoute aux haut-rêvants choisis." + }); - rddCommands.registerCommand({ - path: ["/signe", "-"], func: (content, msg, params) => rddCommands.supprimerSignesDraconiquesEphemeres(), - descr: "Supprime les signes draconiques éphémères" - }); + this.registerCommand({ + path: ["/signe", "-"], func: (content, msg, params) => this.supprimerSignesDraconiquesEphemeres(), + descr: "Supprime les signes draconiques éphémères" + }); - rddCommands.registerCommand({ - path: ["/stress"], func: (content, msg, params) => rddCommands.distribuerStress(params), - descr: `Distribue du stress aux personnages. Exemples: + this.registerCommand({ + path: ["/stress"], func: (content, msg, params) => this.distribuerStress(params), + descr: `Distribue du stress aux personnages. Exemples:
/stress : Ouvre une fenêtre pour donner du stress ou de l'expérience à un ensemble de personnages
/stress 6 : Distribue 6 points des Stress à tout les personnages joueurs, sans raison renseignée
/stress 6 Tigre : Distribue 6 points des Stress à tout les personnages joueurs, à cause d'un Tigre (Vert)
/stress 6 Glou Paulo : Distribue 6 points de Stress au personnage Paulon ou au personnage joueur Paulo, à cause d'un Glou` - }); + }); - rddCommands.registerCommand({ - path: ["/chrono"], func: (content, msg, params) => DialogChronologie.create(), - descr: `Enregistre une entrée de chronologie dans un article de journal` - }); - - game.system.rdd.commands = rddCommands; - } - } - constructor() { - this.commandsTable = {}; + this.registerCommand({ + path: ["/chrono"], func: (content, msg, params) => DialogChronologie.create(), + descr: `Enregistre une entrée de chronologie dans un article de journal` + }); } /* -------------------------------------------- */ registerCommand(command) { - this._addCommand(this.commandsTable, command.path, '', command); + this._addCommand(this.getCommands(), command.path, '', command); + } + + getCommands() { + if (!this.commandsTable){ + this._registerCommands(); + } + return this.commandsTable; } /* -------------------------------------------- */ @@ -194,7 +209,7 @@ export class RdDCommands { } process(command, params, content, msg) { - return this._processCommand(this.commandsTable, command, params, content, msg); + return this._processCommand(this.getCommands(), command, params, content, msg); } async _processCommand(commandsTable, name, params, content = '', msg = {}, path = "") { @@ -225,7 +240,7 @@ export class RdDCommands { } async help(msg, table) { let commands = [] - this._buildSubTableHelp(commands, table || this.commandsTable); + this._buildSubTableHelp(commands, table ?? this.getCommands()); let html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/settings/dialog-aide-commands.html", { commands: commands }); let d = new Dialog( @@ -265,7 +280,7 @@ export class RdDCommands { /* -------------------------------------------- */ async getRencontreTMR(params) { if (params.length == 1 || params.length == 2) { - return game.system.rencontresTMR.rollRencontre(params[0], params[1]) + return game.system.rdd.rencontresTMR.rollRencontre(params[0], params[1]) } return false; } @@ -351,6 +366,7 @@ export class RdDCommands { } return false; } + async tableRencontres(msg, params) { if (params && params.length > 0) { const search = Misc.join(params, ' '); @@ -358,11 +374,29 @@ export class RdDCommands { if (solvedTerrain == undefined) { return RdDCommands._chatAnswer(msg, 'Aucune TMR correspondant à ' + search); } - return game.system.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-confirm.js b/module/rdd-confirm.js index 6fe5579d..c0a480b1 100644 --- a/module/rdd-confirm.js +++ b/module/rdd-confirm.js @@ -45,7 +45,7 @@ export class RdDConfirm { return { "actionSave": { icon: '', - label: "Toujours "+ options.buttonLabel.toLowerCase(), + label: options.buttonLabel + "
et ne plus demander", callback: () => { ReglesOptionelles.set(options.settingConfirmer, false); options.onAction(); diff --git a/module/rdd-herbes.js b/module/rdd-herbes.js index 18b5fad5..5210e03e 100644 --- a/module/rdd-herbes.js +++ b/module/rdd-herbes.js @@ -13,7 +13,7 @@ export class RdDHerbes extends Item { } static async listCategorieHerbes(categorie) { - const herbes = await SystemCompendiums.getWorldOrCompendiumItems('herbe', 'botanique'); + const herbes = await SystemCompendiums.getWorldOrCompendiumItems('herbe', 'faune-flore-mineraux'); return herbes.filter(it => Grammar.equalsInsensitive(it.system.categorie, categorie)); } 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..606b9ed0 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); @@ -46,50 +46,57 @@ export class RdDRollTables { /* -------------------------------------------- */ static async getSouffle(toChat = false) { - return await RdDRollTables.listOrRoll('souffles-de-dragon', 'Item', 'souffle', toChat); + return await RdDRollTables.listOrRoll('souffles-de-dragon', 'Item', ['souffle'], toChat); } /* -------------------------------------------- */ static async getQueue(toChat = false) { - return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', 'queue', toChat); + return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', ['queue'], toChat); } 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'); } /* -------------------------------------------- */ static async getTeteHR(toChat = false) { - return await RdDRollTables.listOrRoll('tetes-de-dragon-pour-haut-revants', 'Item', 'tete', toChat); + return await RdDRollTables.listOrRoll('tetes-de-dragon-pour-haut-revants', 'Item', ['tete'], toChat); } /* -------------------------------------------- */ static async getTete(toChat = false) { - return await RdDRollTables.listOrRoll('tetes-de-dragon-pour-tous-personnages', 'Item', 'tete', toChat); + return await RdDRollTables.listOrRoll('tetes-de-dragon-pour-tous-personnages', 'Item', ['tete'], toChat); } /* -------------------------------------------- */ static async getOmbre(toChat = false) { - return await RdDRollTables.listOrRoll('ombres-de-thanatos', 'Item', 'ombre', toChat); + return await RdDRollTables.listOrRoll('ombres-de-thanatos', 'Item', ['ombre'], toChat); } /* -------------------------------------------- */ static async getTarot(toChat = true) { - return await RdDRollTables.listOrRoll('tarot-draconique', 'Item', 'tarot', toChat); + return await RdDRollTables.listOrRoll('tarot-draconique', 'Item', ['tarot'], toChat); } /* -------------------------------------------- */ - static async listOrRoll(compendium, type, subType, toChat, itemFrequence = it => it.system.frequence, filter = it => true) { + static async listOrRoll(compendium, type, subTypes, toChat, itemFrequence = it => it.system.frequence, filter = it => true) { + const table = new CompendiumTable(compendium, type, subTypes); 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-tmr-dialog.js b/module/rdd-tmr-dialog.js index 0c5e0439..341191ca 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -575,7 +575,7 @@ export class RdDTMRDialog extends Dialog { async _jetDeRencontre(tmr) { let rencontre = this.lookupRencontreExistente(tmr); if (rencontre) { - return game.system.rencontresTMR.calculRencontre(rencontre, tmr); + return game.system.rdd.rencontresTMR.calculRencontre(rencontre, tmr); } let locTMR = (this.isDemiReveCache() ? TMRUtility.getTMRType(tmr.coord) + " ??" @@ -584,7 +584,7 @@ export class RdDTMRDialog extends Dialog { let myRoll = await RdDDice.rollTotal("1dt", { showDice: SHOW_DICE }); if (myRoll == 7) { this._tellToUser(myRoll + ": Rencontre en " + locTMR); - return await game.system.rencontresTMR.getRencontreAleatoire(tmr, this.actor.isMauvaiseRencontre()) + return await game.system.rdd.rencontresTMR.getRencontreAleatoire(tmr, this.actor.isMauvaiseRencontre()) } else { this._tellToUser(myRoll + ": Pas de rencontre en " + locTMR); } diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 1525b460..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,6 +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', @@ -323,7 +329,10 @@ 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); } @@ -459,7 +468,7 @@ export class RdDUtility { formData.ingredients = this.arrayOrEmpty(itemTypes['ingredient']); formData.herbes = this.arrayOrEmpty(itemTypes['herbe']); formData.monnaie = this.arrayOrEmpty(itemTypes['monnaie']); - formData.monnaie.sort(Monnaie.triValeurDenier()); + formData.monnaie.sort(Monnaie.triValeurEntiere()); formData.nourritureboissons = this.arrayOrEmpty(itemTypes['nourritureboisson']); formData.gemmes = this.arrayOrEmpty(itemTypes['gemme']); @@ -545,8 +554,7 @@ export class RdDUtility { if (!profondeur) profondeur = 1; objet.niveau = profondeur; const display = afficherContenu ? 'item-display-show' : 'item-display-hide'; - //console.log("ITEM DISPLAYED", objet ); - let strContenu = `