From 9621d72f923a8de1b977c87c70698c181dacb694 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 7 Oct 2022 19:05:56 +0200 Subject: [PATCH 1/6] Correction des monnaies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Des deniers sont créés si on n'a rien d'autre * Gagner ou dépenser de l'argent fonctionne même si on n'a pas tous les types de pièces * Tous les acteurs peuvent acheter/vendre s'ils ont de l'argent => Pratique pour créer une auberge! * Seuls les personnages peuvent boire et manger * plus de problèmes de monnaies manquantes --- module/actor.js | 67 +++++---------------- module/dialog-item-achat.js | 81 ++++++++++++-------------- module/dialog-item-vente.js | 4 +- module/item-monnaie.js | 99 ++++++++++++++++++++------------ module/item.js | 31 +++++----- module/rdd-utility.js | 12 ++-- templates/dialog-item-achat.html | 62 ++++++++++---------- 7 files changed, 166 insertions(+), 190 deletions(-) diff --git a/module/actor.js b/module/actor.js index bcd34914..ab1aee95 100644 --- a/module/actor.js +++ b/module/actor.js @@ -116,17 +116,13 @@ export class RdDActor extends Actor { const isPersonnage = actorData.type == "personnage"; // If the created actor has items (only applicable to duplicated actors) bypass the new actor creation logic if (actorData.items) { - let actor = await super.create(actorData, options); - if (isPersonnage) { - await actor.checkMonnaiePresence(); - } - return actor; + return await super.create(actorData, options); } if (isPersonnage) { const competences = await RdDUtility.loadCompendium(RdDItemCompetence.actorCompendium(actorData.type)); actorData.items = competences.map(i => i.toObject()); - actorData.items = actorData.items.concat(Monnaie.monnaiesData()); + actorData.items = actorData.items.concat(Monnaie.monnaiesStandard()); } else { actorData.items = []; @@ -180,8 +176,6 @@ export class RdDActor extends Actor { await this.cleanupConteneurs(); await this.computeEncombrementTotalEtMalusArmure(); this.computeEtatGeneral(); - // Sanity check - await this.checkMonnaiePresence(); } /* -------------------------------------------- */ @@ -194,15 +188,6 @@ export class RdDActor extends Actor { } } - /* -------------------------------------------- */ - async checkMonnaiePresence() { // Ajout opportuniste si les pièces n'existent pas. - if (!this.items) return; // Sanity check during import - let manquantes = Monnaie.monnaiesManquantes(this); - if (manquantes.length > 0) { - await this.createEmbeddedDocuments('Item', manquantes, { renderSheet: false }); - } - } - /* -------------------------------------------- */ isCreature() { return this.type == 'creature' || this.type == 'entite'; @@ -3610,33 +3595,11 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ getFortune() { - let monnaies = this.itemTypes['monnaie']; - if (monnaies.length < 4) { - ui.notifications.error("Problème de monnaies manquantes, impossible de payer correctement!") - throw "Problème de monnaies manquantes, impossible de payer correctement!"; - } - return monnaies.map(m => Number(m.system.valeur_deniers) * Number(m.system.quantite)) + return this.itemTypes['monnaie'] + .map(m => Number(m.system.valeur_deniers) * Number(m.system.quantite)) .reduce(Misc.sum(), 0); } - /* -------------------------------------------- */ - async optimizeArgent(fortuneTotale) { - let monnaies = this.itemTypes['monnaie']; - let parValeur = Misc.classifyFirst(monnaies, it => it.system.valeur_deniers); - let nouvelleFortune = { - 1000: Math.floor(fortuneTotale / 1000), // or - 100: Math.floor(fortuneTotale / 100) % 10, // argent - 10: Math.floor(fortuneTotale / 10) % 10, // bronze - 1: fortuneTotale % 10 // étain - } - console.log('RdDActor.optimizeArgent', fortuneTotale, 'nouvelleFortune', nouvelleFortune, 'monnaie_par_valeur', parValeur); - let updates = []; - for (const [valeur, nombre] of Object.entries(nouvelleFortune)) { - updates.push({ _id: parValeur[valeur].id, 'system.quantite': nombre }); - } - await this.updateEmbeddedDocuments('Item', updates); - } - /* -------------------------------------------- */ async depenserDeniers(depense, dataObj = undefined, quantite = 1, toActorId) { depense = Number(depense); @@ -3653,10 +3616,9 @@ export class RdDActor extends Actor { } else { if (fortune >= depense) { - fortune -= depense; const toActor = game.actors.get(toActorId) await toActor?.ajouterDeniers(depense, this.id); - await this.optimizeArgent(fortune); + 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 @@ -3679,18 +3641,19 @@ export class RdDActor extends Actor { } async depenser(depense) { - depense = Number(depense); - let fortune = this.getFortune(); - let reste = fortune - depense; + let reste = this.getFortune() - Number.parseInt(depense); if (reste >= 0) { - fortune -= depense; - await this.optimizeArgent(fortune); + await Monnaie.optimiser(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`); + return; + } if (gain == 0) { return; } @@ -3703,9 +3666,7 @@ export class RdDActor extends Actor { } else { const fromActor = game.actors.get(fromActorId) - let fortune = this.getFortune(); - fortune += gain; - await this.optimizeArgent(fortune); + await Monnaie.optimiser(this, gain + this.getFortune()); RdDAudio.PlayContextAudio("argent"); // Petit son ChatMessage.create({ @@ -3744,8 +3705,8 @@ export class RdDActor extends Actor { const vendeur = achat.vendeurId ? game.actors.get(achat.vendeurId) : undefined; const messageVente = game.messages.get(achat.chatMessageIdVente); const html = await messageVente.getHTML(); - const buttonAcheter = html.find(".button-acheter")[0]; - const vente = DialogItemAchat.prepareVenteData(buttonAcheter, achat.vendeurId, vendeur, acheteur); + const button = html.find(".button-acheter")[0]; + const vente = DialogItemAchat.venteData(button); const itemId = vente.item._id; const isItemEmpilable = "quantite" in vente.item.system; diff --git a/module/dialog-item-achat.js b/module/dialog-item-achat.js index 8b10e7b9..a7c3ec91 100644 --- a/module/dialog-item-achat.js +++ b/module/dialog-item-achat.js @@ -1,34 +1,52 @@ +import { Monnaie } from "./item-monnaie.js"; import { Misc } from "./misc.js"; import { RdDUtility } from "./rdd-utility.js"; export class DialogItemAchat extends Dialog { - static async onButtonAcheter(event) { - const buttonAcheter = event.currentTarget; - if (!buttonAcheter.attributes['data-jsondata']?.value) { - ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes") - return; - } - const chatMessageIdVente = RdDUtility.findChatMessageId(buttonAcheter); - - const vendeurId = buttonAcheter.attributes['data-vendeurId']?.value; + static venteData(button) { + const vendeurId = button.attributes['data-vendeurId']?.value; const vendeur = vendeurId ? game.actors.get(vendeurId) : undefined; const acheteur = RdDUtility.getSelectedActor(); - + const json = button.attributes['data-jsondata']?.value; if (!acheteur && !vendeur) { ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement"); - return; + return undefined; + } + if (!json) { + ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes") + return undefined; } - let venteData = DialogItemAchat.prepareVenteData(buttonAcheter, vendeurId, vendeur, acheteur); + const prixLot = Monnaie.arrondiDeniers(button.attributes['data-prixLot']?.value ?? 0); + return { + item: json ? JSON.parse(json) : undefined, + vendeurId: vendeurId, + vendeur: vendeur, + acheteur: acheteur, + tailleLot: parseInt(button.attributes['data-tailleLot']?.value ?? 1), + quantiteIllimite: button.attributes['data-quantiteIllimite']?.value == 'true', + quantiteNbLots: parseInt(button.attributes['data-quantiteNbLots']?.value), + choix: { + nombreLots: 1, + seForcer: false, + supprimerSiZero: true + }, + prixLot: prixLot, + prixTotal: prixLot, + isVente: prixLot > 0, + chatMessageIdVente: RdDUtility.findChatMessageId(button) + }; + } + static async onAcheter(venteData) { const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData); - const dialog = new DialogItemAchat(html, vendeur, acheteur, venteData, chatMessageIdVente); + const dialog = new DialogItemAchat(html, venteData); dialog.render(true); } - constructor(html, vendeur, acheteur, venteData, chatMessageIdVente) { - const isConsommable = venteData.item.type == 'nourritureboisson'; + constructor(html, venteData) { + const isConsommable = venteData.item.type == 'nourritureboisson' && venteData.acheteur?.isPersonnage(); let options = { classes: ["dialogachat"], width: 400, height: isConsommable ? 450 : 350, 'z-index': 99999 }; const actionAchat = venteData.prixLot > 0 ? "Acheter" : "Prendre"; @@ -47,42 +65,17 @@ export class DialogItemAchat extends Dialog { super(conf, options); - this.vendeur = vendeur; - this.acheteur = acheteur; - this.chatMessageIdVente = chatMessageIdVente; this.venteData = venteData; } - static prepareVenteData(buttonAcheter, vendeurId, vendeur, acheteur) { - const jsondata = buttonAcheter.attributes['data-jsondata']?.value; - const prixLot = parseInt(buttonAcheter.attributes['data-prixLot']?.value ?? 0); - return { - item: JSON.parse(jsondata), - vendeurId: vendeurId, - vendeur: vendeur, - acheteur: acheteur, - tailleLot: parseInt(buttonAcheter.attributes['data-tailleLot']?.value ?? 1), - quantiteIllimite: buttonAcheter.attributes['data-quantiteIllimite']?.value == 'true', - quantiteNbLots: parseInt(buttonAcheter.attributes['data-quantiteNbLots']?.value), - choix: { - nombreLots: 1, - seForcer: false, - supprimerSiZero: true - }, - prixLot: prixLot, - prixTotal: prixLot, - isVente: prixLot > 0 - }; - } - async onAchat() { await $(".nombreLots").change(); - (this.vendeur ?? this.acheteur).achatVente({ + (this.venteData.vendeur ?? this.venteData.acheteur).achatVente({ userId: game.user.id, - vendeurId: this.vendeur?.id, - acheteurId: this.acheteur?.id, + vendeurId: this.venteData.vendeur?.id, + acheteurId: this.venteData.acheteur?.id, prixTotal: this.venteData.prixTotal, - chatMessageIdVente: this.chatMessageIdVente, + chatMessageIdVente: this.venteData.chatMessageIdVente, choix: this.venteData.choix }); } diff --git a/module/dialog-item-vente.js b/module/dialog-item-vente.js index 3dba68d0..2b2ebdcd 100644 --- a/module/dialog-item-vente.js +++ b/module/dialog-item-vente.js @@ -3,7 +3,7 @@ import { Misc } from "./misc.js"; export class DialogItemVente extends Dialog { - static async create(item, callback) { + static async display(item, callback) { const quantite = item.isConteneur() ? 1 : item.system.quantite; const venteData = { item: item, @@ -20,7 +20,7 @@ export class DialogItemVente extends Dialog { isOwned: item.isOwned, }; const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.html`, venteData); - return new DialogItemVente(venteData, html, callback); + return new DialogItemVente(venteData, html, callback).render(true); } constructor(venteData, html, callback) { diff --git a/module/item-monnaie.js b/module/item-monnaie.js index df3e2454..b1a57e66 100644 --- a/module/item-monnaie.js +++ b/module/item-monnaie.js @@ -1,44 +1,32 @@ import { Misc } from "./misc.js"; -import { LOG_HEAD, SYSTEM_RDD } from "./constants.js"; +import { LOG_HEAD } from "./constants.js"; -const MONNAIES_STANDARD = [ - { - 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: "" } - }, - { - 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: "" } - }, - { - 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: "" } - }, - { - 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: "" } - } -] -const VALEURS_STANDARDS = MONNAIES_STANDARD.map(it =>it.system.valeur_deniers); +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: "" } +}; +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: "" } +}; +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: "" } +}; +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: "" } +}; + +const MONNAIES_STANDARD = [MONNAIE_ETAIN, MONNAIE_BRONZE, MONNAIE_ARGENT, MONNAIE_OR]; export class Monnaie { - static isSystemMonnaie(item, items) { - if (item.type == 'monnaie') { - const valeur = item.system.valeur_deniers; - if (VALEURS_STANDARDS.includes(valeur)) { - const monnaiesDeValeur = items.filter(it => it.type == 'monnaie' && it.system.valeur_deniers == valeur) - return monnaiesDeValeur.length<=1; - } - } - return false; - } - - static monnaiesData() { + static monnaiesStandard() { return MONNAIES_STANDARD; } @@ -56,10 +44,47 @@ export class Monnaie { } static arrondiDeniers(sols) { - return sols.toFixed(2); + return Number(sols).toFixed(2); } static triValeurDenier() { return Misc.ascending(item => item.system.valeur_deniers) } + + static async creerMonnaiesStandard(actor) { + await actor.createEmbeddedDocuments('Item', MONNAIES_STANDARD, { renderSheet: false }); + } + + static async creerMonnaiesDeniers(actor, fortune) { + await actor.createEmbeddedDocuments('Item', [Monnaie.creerDeniers(fortune)], { renderSheet: false }); + } + + static creerDeniers(fortune) { + const deniers = duplicate(MONNAIE_ETAIN); + deniers.system.quantite = fortune; + return deniers; + } + + static async optimiser(actor, fortune) { + let reste = fortune; + 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]) { + if (parValeur[valeur]) { + const piecesDeCetteValeur = Math.floor(reste / valeur); + updates.push({ _id: parValeur[valeur].id, 'system.quantite': piecesDeCetteValeur }); + reste -= piecesDeCetteValeur*valeur; + } + } + console.log('Monnaie.optimiser', actor.name, 'total', fortune, 'parValeur', parValeur, 'updates', updates, 'reste', reste); + if (updates.length > 0) { + await actor.updateEmbeddedDocuments('Item', updates); + } + if (reste>0){ + // créer le reste en deniers fortune en deniers + await Monnaie.creerMonnaiesDeniers(actor, reste); + } + } + } diff --git a/module/item.js b/module/item.js index 48da84f1..22e60a37 100644 --- a/module/item.js +++ b/module/item.js @@ -268,26 +268,23 @@ export class RdDItem extends Item { async proposerVente() { console.log(this); if (this.isConteneurNonVide()) { - ui.notifications.warn(`Votre ${this.name} n'est pas vide, pas possible de le donner ou le vendre`); + ui.notifications.warn(`Votre ${this.name} n'est pas vide, pas possible de le proposer`); return; } - const dialog = await DialogItemVente.create(this, (vente) => this._onProposerVente(vente)) - dialog.render(true); - } - - async _onProposerVente(venteData) { - venteData["properties"] = this.getProprietes(); - if (venteData.isOwned) { - if (venteData.quantiteNbLots * venteData.tailleLot > venteData.quantiteMax) { - ui.notifications.warn(`Vous avez ${venteData.quantiteMax} ${venteData.item.name}, ce n'est pas suffisant pour vendre ${venteData.quantiteNbLots} de ${venteData.tailleLot}`) - return; + await DialogItemVente.display(this, async (vente) => { + vente["properties"] = this.getProprietes(); + if (vente.isOwned) { + if (vente.quantiteNbLots * vente.tailleLot > vente.quantiteMax) { + ui.notifications.warn(`Vous avez ${vente.quantiteMax} ${vente.item.name}, ce n'est pas suffisant pour vendre ${vente.quantiteNbLots} de ${vente.tailleLot}`) + return; + } } - } - venteData.jsondata = JSON.stringify(venteData.item); - - console.log(venteData); - let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', venteData); - ChatMessage.create(RdDUtility.chatDataSetup(html)); + vente.jsondata = JSON.stringify(vente.item); + + console.log(vente); + let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente); + ChatMessage.create(RdDUtility.chatDataSetup(html)); + }); } /* -------------------------------------------- */ diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 1d3632dc..c029cb10 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -750,7 +750,12 @@ export class RdDUtility { }); // gestion bouton tchat Acheter - html.on("click", '.button-acheter', event => DialogItemAchat.onButtonAcheter(event)); + html.on("click", '.button-acheter', event => { + const venteData = DialogItemAchat.venteData(event.currentTarget); + if (venteData) { + DialogItemAchat.onAcheter(venteData); + } + }); html.on("click", '.button-creer-acteur', event => RdDNameGen.onCreerActeur(event)); // Gestion du bouton payer @@ -888,11 +893,6 @@ export class RdDUtility { /* -------------------------------------------- */ static async confirmerSuppressionItem(sheet, item, htmlToDelete) { const itemId = item.id; - if (Monnaie.isSystemMonnaie(item, sheet.actor.items)) { - ui.notifications.warn("Suppression des monnaies de base impossible"); - return; - } - const confirmationSuppression = { settingConfirmer: "confirmation-supprimer-" + item.getItemGroup(), content: `

Etes vous certain de vouloir supprimer: ${item.name}?

`, diff --git a/templates/dialog-item-achat.html b/templates/dialog-item-achat.html index 3363a358..c54eaf55 100644 --- a/templates/dialog-item-achat.html +++ b/templates/dialog-item-achat.html @@ -45,38 +45,38 @@ - {{#if (eq item.type 'nourritureboisson')}} -

- Si vous souhaitez {{#if item.system.boisson}}boire{{else}}manger{{/if}}: -

+ {{#if (and (eq item.type 'nourritureboisson') (eq acheteur.type 'personnage'))}} +

Si vous souhaitez {{#if item.system.boisson}}boire{{else}}manger{{/if}}:

- {{#if item.system.sust}} -

Cette {{#if item.system.boisson}}boisson{{else}}nourriture{{/if}} vous apportera {{totalSust}} de sustantation.

- {{/if}} - {{#if item.system.boisson}} -

{{#if item.system.alcoolise}} - C'est une boisson alcoolisée de force {{item.system.force}}, vous effectuerez un jet d'éthylisme. - {{/if}} - Cette boisson vous apportera {{totalDesaltere}} unités d'eau. -

- {{/if}} - {{#if (gt item.system.qualite 0)}} - {{#if (gt item.system.qualite cuisine.system.niveau)}} -

La qualité du plat est telle qu'un jet de Goût/Cuisine à {{numberFormat item.system.qualite decimals=0 sign=true}} - vous permettra un jet de moral heureux.

- {{/if}} - {{/if}} - - {{#if (or (lt item.system.qualite 0) (lt item.system.exotisme 0))}} -

- Pour surmonter {{#if (lt item.system.qualite 0)}}le mauvais goût{{else}}l'exotisme{{/if}}, vous devez effectuer un jet de Volonté/Cuisine à {{numberFormat (min item.system.exotisme item.system.qualite) decimals=0 sign=true}}. -
- - - -

- {{/if}} + {{#if item.system.sust}} +

Cette {{#if item.system.boisson}}boisson{{else}}nourriture{{/if}} vous apportera + {{totalSust}} + de sustantation.

+ {{/if}} + {{#if item.system.boisson}} +

+ {{#if item.system.alcoolise}} + C'est une boisson alcoolisée de force {{item.system.force}}, vous effectuerez un jet d'éthylisme. + {{/if}} + Cette boisson vous apportera {{totalDesaltere}} unités d'eau. +

+ {{/if}} + {{#if (gt item.system.qualite 0)}} + {{#if (gt item.system.qualite cuisine.system.niveau)}} +

La qualité du plat est telle qu'un jet de Goût/Cuisine à {{numberFormat item.system.qualite decimals=0 sign=true}} + vous permettra un jet de moral heureux.

+ {{/if}} + {{/if}} + + {{#if (or (lt item.system.qualite 0) (lt item.system.exotisme 0))}} +

+ Pour surmonter {{#if (lt item.system.qualite 0)}}le mauvais goût{{else}}l'exotisme{{/if}}, vous devez effectuer un jet de Volonté/Cuisine à {{numberFormat (min item.system.exotisme item.system.qualite) decimals=0 sign=true}}. +
+ + + +

+ {{/if}} {{/if}} {{#if isVente}} From d316bba8fa18524bf99f7947f486469320f5b38b Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 7 Oct 2022 19:06:43 +0200 Subject: [PATCH 2/6] =?UTF-8?q?D=C3=A9placement=20de=20m=C3=A9thode=20comp?= =?UTF-8?q?endium?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/misc.js | 11 ----------- module/rdd-compendium-organiser.js | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/module/misc.js b/module/misc.js index 74acb790..682c9aec 100644 --- a/module/misc.js +++ b/module/misc.js @@ -105,17 +105,6 @@ export class Misc { return params.reduce((a, b) => a + separator + b); } - - static getEntityTypeLabel(entity) { - const documentName = entity?.documentName - const type = entity?.type - if (documentName === 'Actor' || documentName === 'Item') { - const label = CONFIG[documentName]?.typeLabels?.[type] ?? type; - return game.i18n.has(label) ? game.i18n.localize(label) : t; - } - return type; - } - static connectedGMOrUser(ownerId = undefined) { if (ownerId && game.user.id == ownerId) { return ownerId; diff --git a/module/rdd-compendium-organiser.js b/module/rdd-compendium-organiser.js index 56f9a08a..23cac6c7 100644 --- a/module/rdd-compendium-organiser.js +++ b/module/rdd-compendium-organiser.js @@ -1,5 +1,4 @@ import { SYSTEM_RDD } from "./constants.js"; -import { Misc } from "./misc.js"; export class RddCompendiumOrganiser { static init() { @@ -17,7 +16,7 @@ export class RddCompendiumOrganiser { } static async setEntityTypeName(pack, element) { - const label = Misc.getEntityTypeLabel(await pack.getDocument(element.dataset.documentId)); + const label = RddCompendiumOrganiser.getEntityTypeLabel(await pack.getDocument(element.dataset.documentId)); RddCompendiumOrganiser.insertEntityType(element, label); } @@ -27,4 +26,16 @@ export class RddCompendiumOrganiser { } } + + static getEntityTypeLabel(entity) { + const documentName = entity?.documentName + const type = entity?.type + if (documentName === 'Actor' || documentName === 'Item') { + const label = CONFIG[documentName]?.typeLabels?.[type] ?? type; + return game.i18n.has(label) ? game.i18n.localize(label) : t; + } + return type; + } + + } \ No newline at end of file From 4f8406360f61271cdf78bf1d1510d4b5bce24175 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 7 Oct 2022 19:07:16 +0200 Subject: [PATCH 3/6] =?UTF-8?q?Suppression=20de=20cr=C3=A9ation=20de=20per?= =?UTF-8?q?sonnage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit la feuille n'est pas encore prête --- module/rdd-utility.js | 1 - 1 file changed, 1 deletion(-) diff --git a/module/rdd-utility.js b/module/rdd-utility.js index c029cb10..b55ab121 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -112,7 +112,6 @@ export class RdDUtility { static async preloadHandlebarsTemplates() { const templatePaths = [ //Character Sheets - 'systems/foundryvtt-reve-de-dragon/templates/actor-creation-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/actor-creature-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html', From 3e17dd9b7ef3f0f3432af5861780976bf6141d3f Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 7 Oct 2022 23:28:41 +0200 Subject: [PATCH 4/6] =?UTF-8?q?Ajout=20d'informations=20pour=20armes=20?= =?UTF-8?q?=C3=A0=20distance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * prise en compte de la taille de la cible * prise en compte de l'activité * valeur indicative --- module/actor.js | 11 +++-- module/rdd-combat.js | 82 ++++++++++++++++++++++++------- module/rdd-utility.js | 1 + templates/chat-info-distance.html | 9 ++++ 4 files changed, 82 insertions(+), 21 deletions(-) create mode 100644 templates/chat-info-distance.html diff --git a/module/actor.js b/module/actor.js index ab1aee95..387aaab7 100644 --- a/module/actor.js +++ b/module/actor.js @@ -139,9 +139,9 @@ export class RdDActor extends Actor { // Make separate methods for each Actor type (character, npc, etc.) to keep // things organized. - if (this.type === 'personnage') this._prepareCharacterData(this) - if (this.type === 'creature') this._prepareCreatureData(this) - if (this.type === 'vehicule') this._prepareVehiculeData(this) + if (this.isPersonnage()) this._prepareCharacterData(this) + if (this.isCreature()) this._prepareCreatureData(this) + if (this.isVehicule()) this._prepareVehiculeData(this) } /* -------------------------------------------- */ @@ -196,6 +196,9 @@ export class RdDActor extends Actor { isPersonnage() { return this.type == 'personnage'; } + isVehicule() { + return this.type == 'vehicule'; + } /* -------------------------------------------- */ isHautRevant() { return this.isPersonnage() && this.system.attributs.hautrevant.value != "" @@ -4107,7 +4110,7 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async setEffect(statusId, status) { - if (this.isEntite() || this.type == 'vehicule') { + if (this.isEntite() || this.isVehicule()) { return; } console.log("setEffect", statusId, status) diff --git a/module/rdd-combat.js b/module/rdd-combat.js index 268ede40..c0ee78fc 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -1,5 +1,5 @@ import { ChatUtility } from "./chat-utility.js"; -import { ENTITE_INCARNE, ENTITE_NONINCARNE, HIDE_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; +import { ENTITE_BLURETTE, ENTITE_INCARNE, ENTITE_NONINCARNE, HIDE_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; import { Grammar } from "./grammar.js"; import { RdDItemArme } from "./item-arme.js"; import { RdDItemCompetence } from "./item-competence.js"; @@ -688,27 +688,75 @@ export class RdDCombat { } /* -------------------------------------------- */ - verifierDistance( rollData ) { - if ( rollData.competence.system.categorie == "tir" || - rollData.competence.system.categorie == "lancer" ) { - const defenderToken = canvas.tokens.get(this.defenderTokenId) - let dist = canvas.grid.measureDistances([{ ray: new Ray(_token.center, defenderToken.center) }], { gridSpaces: false }) - dist = Number(dist).toPrecision(5) - //let ray = new Ray( {x: _token.x, y: _token.y}, {x: defenderToken.x, y:defenderToken.y} ) - let msgPortee = "portée est courte (0)" - if (dist > rollData.arme.system.portee_courte && dist <= rollData.arme.system.portee_moyenne) { - msgPortee = "portée est moyenne (-3)" - } else if (dist > rollData.arme.system.portee_moyenne && dist <= rollData.arme.system.portee_extreme) { - msgPortee = "portée est extrême (-5)" - } else if ( dist > rollData.arme.system.portee_extreme) { - msgPortee = "cible est inateignable" + async proposerAjustementTirLancer( rollData ) { + if (['tir', 'lancer'].includes(rollData.competence.system.categorie)) { + if (this.defender.isEntite([ENTITE_BLURETTE])){ + ChatMessage.create( { + content: `La cible est une blurette, l'arme à distance sera perdue dans le blurêve`, + whisper: ChatMessage.getWhisperRecipients("GM")}) + } + else { + const defenderToken = canvas.tokens.get(this.defenderTokenId); + const dist = this.distance(_token, defenderToken) + const portee = this._ajustementPortee(dist, rollData.arme) + const taille = this._ajustementTaille(this.defender) + const activite = this._ajustementMouvement(this.defender) + const total = [portee, taille, activite].map(it=>it.diff).filter(d => !Number.isNaN(d)).reduce(Misc.sum(), 0) + ChatMessage.create({ + content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-info-distance.html', { + rollData: rollData, + attacker: _token, + defender: defenderToken, + distance: dist, + portee: portee, + taille: taille, + activite: activite, + total: total + }), + whisper: ChatMessage.getWhisperRecipients("GM") + }) } - ChatMessage.create( { content: `Indication MJ : La cible est à une distance indicative de : ${dist} mètres. Pour l'arme ${rollData.arme.name}, la ${msgPortee}.`, whisper: ChatMessage.getWhisperRecipients("GM") } ) } } + distance(t, defenderToken) { + return Number(canvas.grid.measureDistances([{ ray: new Ray(t.center, defenderToken.center) }], { gridSpaces: false })).toFixed(1); + } + + _ajustementPortee(dist, arme) { + if (dist <= arme.system.portee_courte) return {msg:"courte", diff:0}; + if (dist <= arme.system.portee_moyenne) return {msg: "moyenne" , diff: -3}; + if (dist <= arme.system.portee_extreme) return {msg: "extrême", diff:-5}; + return {msg: "inatteignable", diff: '‐'}; + } + + _ajustementTaille(actor) { + if (actor.isVehicule()) return {msg: "véhicule", diff: 0} + const taille = actor.getCaracByName('TAILLE')?.value ?? 1; + if (taille <= 1) return {msg: "souris", diff: -8}; + if (taille <= 3) return {msg: "chat", diff: -4}; + if (taille <= 5) return {msg: "chien", diff: -2}; + if (taille <= 15) return {msg: "humanoïde", diff: 0}; + if (taille <= 20) return {msg: "ogre", diff: 2}; + return {msg: "gigantesque", diff: 4}; + } + _ajustementMouvement(defender) { + if (defender.getSurprise(true)) return {msg: "immobile (surprise)", diff: 0}; + if (game.combat?.combatants.find(it => it.actorId == defender.id)) return {msg: "en mouvement (combat)", diff: -4}; + return {msg: "à déterminer (0 immobile, -3 actif, -4 en mouvement, -5 en zig-zag)", diff: -3}; + } + /* -------------------------------------------- */ async attaque(competence, arme) { + // const nonIncarnee = this.defender.isEntite([ENTITE_NONINCARNE]) + // const blurette = this.defender.isEntite([ENTITE_BLURETTE]) + // if (nonIncarnee || blurette) { + // ChatMessage.create( { + // content: `La cible est ${nonIncarnee ? 'non incarnée' : 'une blurette'}. + // Il est impossible de l'atteindre.`, + // whisper: ChatMessage.getWhisperRecipients("GM")}) + // } + if (!await this.accorderEntite('avant-attaque')) { return; } @@ -729,7 +777,7 @@ export class RdDCombat { if (arme) { this.attacker.verifierForceMin(arme); } - this.verifierDistance(rollData) + await this.proposerAjustementTirLancer(rollData) const dialog = await RdDRoll.create(this.attacker, rollData, { diff --git a/module/rdd-utility.js b/module/rdd-utility.js index b55ab121..80be7814 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -241,6 +241,7 @@ export class RdDUtility { 'systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-description.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-info-appel-au-moral.html', + 'systems/foundryvtt-reve-de-dragon/templates/chat-info-distance.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-particuliere.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.html', diff --git a/templates/chat-info-distance.html b/templates/chat-info-distance.html new file mode 100644 index 00000000..8cc89e5b --- /dev/null +++ b/templates/chat-info-distance.html @@ -0,0 +1,9 @@ +{{rollData.arme.name}} +Ajustement de tir/lancer proposé de {{total}} +
    +
  • {{defender.name}} est à une distance indicative de {{distance}} mètres.
  • + {{log defender}} +
  • Portée {{portee.msg}} pour l'arme {{rollData.arme.name}} : {{portee.diff}}
  • +
  • De taille {{taille.msg}}: {{taille.diff}}
  • +
  • Mouvement {{activite.msg}}: {{activite.diff}}
  • +
From 35f1f2437c40ea33eb1516a9f1977cc978afcfec Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 7 Oct 2022 23:30:06 +0200 Subject: [PATCH 5/6] Garde fous MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit En cas d'exception dans le traitement d'un message websocket, faire un catch pour être sûr de ne pas réémettre si l'exception revient à l'émetteur (boucle infinie d'envois sinon) --- module/rdd-main.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/module/rdd-main.js b/module/rdd-main.js index cfb87b59..d7466074 100644 --- a/module/rdd-main.js +++ b/module/rdd-main.js @@ -150,11 +150,14 @@ Hooks.once("init", async function () { /* -------------------------------------------- */ game.socket.on(SYSTEM_SOCKET_ID, sockmsg => { console.log(">>>>> MSG RECV", sockmsg); - - RdDUtility.onSocketMessage(sockmsg); - RdDCombat.onSocketMessage(sockmsg); - ChatUtility.onSocketMessage(sockmsg); - RdDActor.onSocketMessage(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) + } }); /* -------------------------------------------- */ From 0dcce5456b2c0f7ca0c85c8bf578a1edae620ad8 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 7 Oct 2022 23:31:57 +0200 Subject: [PATCH 6/6] =?UTF-8?q?Inatteignable=20=C3=A0=20-10?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit au lieu de hyphen non affiché --- module/rdd-combat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/rdd-combat.js b/module/rdd-combat.js index c0ee78fc..5ef5b77d 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -727,7 +727,7 @@ export class RdDCombat { if (dist <= arme.system.portee_courte) return {msg:"courte", diff:0}; if (dist <= arme.system.portee_moyenne) return {msg: "moyenne" , diff: -3}; if (dist <= arme.system.portee_extreme) return {msg: "extrême", diff:-5}; - return {msg: "inatteignable", diff: '‐'}; + return {msg: "inatteignable", diff: -10}; } _ajustementTaille(actor) {