From d77ecee9bd3d00fe784931abb0c272e05c36306e Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 31 Dec 2022 18:57:01 +0100 Subject: [PATCH 01/18] Fix: exaltation/dissolution --- templates/actor/carac-derivee.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/actor/carac-derivee.html b/templates/actor/carac-derivee.html index c50c7b75..ff40ecaa 100644 --- a/templates/actor/carac-derivee.html +++ b/templates/actor/carac-derivee.html @@ -24,9 +24,9 @@
  • - + - +
  • -- 2.35.3 From 2ca601b5f800e2e5d8dabd04d2250cd774732436 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 1 Jan 2023 22:18:18 +0100 Subject: [PATCH 02/18] onDrop depuis compendium async Permettre de retrouver l'Item du compendium pour tester si un acteur peut le recevoir --- module/actor/base-actor-sheet.js | 2 +- module/item-conteneur-sheet.js | 2 +- module/rdd-sheet-utility.js | 9 +++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/module/actor/base-actor-sheet.js b/module/actor/base-actor-sheet.js index 98cd8650..30dcf9a7 100644 --- a/module/actor/base-actor-sheet.js +++ b/module/actor/base-actor-sheet.js @@ -185,7 +185,7 @@ export class RdDBaseActorSheet extends ActorSheet { /* -------------------------------------------- */ async _onDropItem(event, dragData) { const destItemId = this.html.find(event.target)?.closest('.item').attr('data-item-id') - const dropParams = RdDSheetUtility.prepareItemDropParameters(destItemId, this.actor, dragData, this.objetVersConteneur) + const dropParams = await RdDSheetUtility.prepareItemDropParameters(destItemId, this.actor, dragData, this.objetVersConteneur) if (dropParams) { const callSuper = await this.actor.processDropItem(dropParams) if (callSuper) { diff --git a/module/item-conteneur-sheet.js b/module/item-conteneur-sheet.js index 0df3121a..e545cadf 100644 --- a/module/item-conteneur-sheet.js +++ b/module/item-conteneur-sheet.js @@ -51,7 +51,7 @@ export class RdDConteneurItemSheet extends RdDItemSheet { async _onDropItem(event, dragData) { if (this.actor) { - const dropParams = RdDSheetUtility.prepareItemDropParameters(this.item.id, this.actor, dragData, this.objetVersConteneur); + const dropParams = await RdDSheetUtility.prepareItemDropParameters(this.item.id, this.actor, dragData, this.objetVersConteneur); await this.actor.processDropItem(dropParams); await this.render(true); } diff --git a/module/rdd-sheet-utility.js b/module/rdd-sheet-utility.js index faa6856d..e1090a04 100644 --- a/module/rdd-sheet-utility.js +++ b/module/rdd-sheet-utility.js @@ -1,4 +1,6 @@ import { DialogSplitItem } from "./dialog-split-item.js"; +import { RdDItem } from "./item.js"; +import { SystemCompendiums } from "./settings/system-compendiums.js"; export class RdDSheetUtility { @@ -19,8 +21,11 @@ export class RdDSheetUtility { return $(event.currentTarget)?.parents(".item"); } - static prepareItemDropParameters(destItemId, actor, dragData, objetVersConteneur) { - const item = fromUuidSync(dragData.uuid) + static async prepareItemDropParameters(destItemId, actor, dragData, objetVersConteneur) { + let item = fromUuidSync(dragData.uuid); + if (item.pack && !item.system){ + item = await RdDItem.getCorrespondingItem(item); + } if (actor.canReceive(item)) { return { destId: destItemId, -- 2.35.3 From fbd3aa7121ef9db7a8eacedcc971fa4f87a87d92 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 1 Jan 2023 22:20:26 +0100 Subject: [PATCH 03/18] =?UTF-8?q?Extraction=20des=20settings=20dans=20une?= =?UTF-8?q?=20m=C3=A9thode=20d=C3=A9di=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/rdd-main.js | 153 +++++++++++++++++++++++---------------------- 1 file changed, 79 insertions(+), 74 deletions(-) diff --git a/module/rdd-main.js b/module/rdd-main.js index b1799ce7..7d68790f 100644 --- a/module/rdd-main.js +++ b/module/rdd-main.js @@ -77,80 +77,7 @@ export class SystemReveDeDragon { RdDUtility.preloadHandlebarsTemplates(); /* -------------------------------------------- */ - game.settings.register(SYSTEM_RDD, "accorder-entite-cauchemar", { - name: "Accorder le rêve aux entités", - hint: "A quel moment les personnages doivent accorder leur rêve aux entités de cauchemar", - scope: "world", - config: true, - type: String, - choices: { // If choices are defined, the resulting setting will be a select menu - "avant-attaque": "Avant l'attaque", - "avant-defense": "Avant la défense", - "avant-encaissement": "Avant l'encaissement", - }, - default: "avant-encaissement" - }); - - /* -------------------------------------------- */ - game.settings.register(SYSTEM_RDD, "calendrier", { - name: "calendrier", - scope: "world", - config: false, - default: RdDCalendrier.createCalendrierInitial(), - type: Object - }); - - /* -------------------------------------------- */ - game.settings.register(SYSTEM_RDD, "liste-nombre-astral", { - name: "liste-nombre-astral", - scope: "world", - config: false, - default: [], - type: Object - }); - - /* -------------------------------------------- */ - game.settings.register(SYSTEM_RDD, "calendrier-pos", { - name: "calendrierPos", - scope: "client", - config: false, - default: RdDCalendrier.createCalendrierPos(), - type: Object - }); - - - /* -------------------------------------------- */ - game.settings.register(SYSTEM_RDD, "supprimer-dialogues-combat-chat", { - name: "Supprimer les dialogues de combat", - hint: "Si désactivée, tous les dialogues de combat sont conservés dans la conversation", - scope: "world", - config: true, - default: true, - type: Boolean - }); - /* -------------------------------------------- */ - game.settings.register(SYSTEM_RDD, "activer-sons-audio", { - name: "Activer les bruitages intégrés", - hint: "Si activé, certaines actions en jeu déclenchent un son d'ambiance", - scope: "world", - config: true, - default: true, - type: Boolean - }); - /* -------------------------------------------- */ - game.settings.register(SYSTEM_RDD, "appliquer-famine-soif", { - name: "Notifier de la famine et la soif pour", - hint: "Indique si les cas de famine et de soif seront indiqués durant Château Dormant", - scope: "world", - config: true, - type: String, - choices: { - "aucun": "ni la famine, ni la soif", - "famine": "seulement la famine", - "famine-soif": "la famine et la soif", - }, - default: "aucun" - }); + this.initSystemSettings(); /* -------------------------------------------- */ // Set an initiative formula for the system @@ -235,6 +162,84 @@ export class SystemReveDeDragon { Hooks.once('ready', () => this.onReady()); } + initSystemSettings() { + game.settings.register(SYSTEM_RDD, "accorder-entite-cauchemar", { + name: "Accorder le rêve aux entités", + hint: "A quel moment les personnages doivent accorder leur rêve aux entités de cauchemar", + scope: "world", + config: true, + type: String, + choices: { + "avant-attaque": "Avant l'attaque", + "avant-defense": "Avant la défense", + "avant-encaissement": "Avant l'encaissement", + }, + default: "avant-encaissement" + }); + + /* -------------------------------------------- */ + game.settings.register(SYSTEM_RDD, "calendrier", { + name: "calendrier", + scope: "world", + config: false, + default: RdDCalendrier.createCalendrierInitial(), + type: Object + }); + + /* -------------------------------------------- */ + game.settings.register(SYSTEM_RDD, "liste-nombre-astral", { + name: "liste-nombre-astral", + scope: "world", + config: false, + default: [], + type: Object + }); + + /* -------------------------------------------- */ + game.settings.register(SYSTEM_RDD, "calendrier-pos", { + name: "calendrierPos", + scope: "client", + config: false, + default: RdDCalendrier.createCalendrierPos(), + type: Object + }); + + + /* -------------------------------------------- */ + game.settings.register(SYSTEM_RDD, "supprimer-dialogues-combat-chat", { + name: "Supprimer les dialogues de combat", + hint: "Si désactivée, tous les dialogues de combat sont conservés dans la conversation", + scope: "world", + config: true, + default: true, + type: Boolean + }); + + /* -------------------------------------------- */ + game.settings.register(SYSTEM_RDD, "activer-sons-audio", { + name: "Activer les bruitages intégrés", + hint: "Si activé, certaines actions en jeu déclenchent un son d'ambiance", + scope: "world", + config: true, + default: true, + type: Boolean + }); + /* -------------------------------------------- */ + game.settings.register(SYSTEM_RDD, "appliquer-famine-soif", { + name: "Notifier de la famine et la soif pour", + hint: "Indique si les cas de famine et de soif seront indiqués durant Château Dormant", + scope: "world", + config: true, + type: String, + choices: { + "aucun": "ni la famine, ni la soif", + "famine": "seulement la famine", + "famine-soif": "la famine et la soif", + }, + default: "aucun" + }); + } + async onReady() { /* -------------------------------------------- */ -- 2.35.3 From 7f5b2e0abf2806a3a01cb5776b27b19b7711bf94 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Mon, 2 Jan 2023 01:36:26 +0100 Subject: [PATCH 04/18] Cleanup --- templates/settings/system-compendiums.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/templates/settings/system-compendiums.html b/templates/settings/system-compendiums.html index 089c6fb5..74e85cd3 100644 --- a/templates/settings/system-compendiums.html +++ b/templates/settings/system-compendiums.html @@ -1,6 +1,4 @@
    - {{log 'systemCompendiums'systemCompendiums}} - {{log 'availableCompendiums' availableCompendiums}}
      {{#each systemCompendiums as |definition key|}}
    • -- 2.35.3 From d7e5a0954078724f6de01b1cd1d62d19ac58d5b6 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Mon, 2 Jan 2023 01:37:08 +0100 Subject: [PATCH 05/18] Permettre de regrouper des herbes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L'environnement est un tableau, dur à comparer --- module/item.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/item.js b/module/item.js index 95fadacf..8455a733 100644 --- a/module/item.js +++ b/module/item.js @@ -365,7 +365,7 @@ export class RdDItem extends Item { await item.delete(); } - async quantiteIncDec(nombre, options = { diminuerQuantite: true, supprimerSiZero: false }) { + async quantiteIncDec(nombre, options = { supprimerSiZero: false }) { const quantite = Number(this.system.quantite ?? -1); if (quantite >= 0) { const reste = Math.max(quantite + Number(nombre), 0); @@ -402,7 +402,7 @@ export class RdDItem extends Item { return [false, `Impossible de regrouper ${this.name} avec ${other.name}`]; } else { - const excludedProperties = ['quantite', 'cout', 'encTotal']; + const excludedProperties = ['quantite', 'cout', 'encTotal', 'environnement']; if (this.isComestible()) { excludedProperties.push('sust', 'encombrement'); } -- 2.35.3 From 274009d3fa9f9d70a422ca348b2f633d7cd619d9 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 1 Jan 2023 22:16:26 +0100 Subject: [PATCH 06/18] Suppression de vente depuis un "service" --- module/actor.js | 18 +++++++----------- module/actor/base-actor-sheet.js | 7 +++++-- module/dialog-item-achat.js | 7 ++----- module/dialog-item-vente.js | 12 +++++------- module/item-service.js | 2 +- module/item-sheet.js | 2 +- module/item.js | 3 +-- templates/dialog-item-achat.html | 4 +--- 8 files changed, 23 insertions(+), 32 deletions(-) diff --git a/module/actor.js b/module/actor.js index f532d894..8b85cdce 100644 --- a/module/actor.js +++ b/module/actor.js @@ -3661,12 +3661,11 @@ export class RdDActor extends RdDBaseActor { const cout = Number(achat.prixTotal ?? 0); const vendeur = achat.vendeurId ? game.actors.get(achat.vendeurId) : undefined; - const service = achat.serviceId ? (vendeur?.getItem(achat.serviceId) ?? game.items.get(achat.serviceId)) : undefined; const acheteur = achat.acheteurId ? game.actors.get(achat.acheteurId) : undefined; const vente = achat.vente; const quantite = (achat.choix.nombreLots ?? 1) * (vente.tailleLot); const itemVendu = vendeur?.getItem(vente.item._id) ?? (await RdDItem.getCorrespondingItem(vente.item)); - if (!this.verifierQuantite(service, vente.serviceSubItem, vendeur, itemVendu, quantite)) { + if (!this.verifierQuantite(vendeur, itemVendu, quantite)) { ChatUtility.notifyUser(achat.userId, 'warn', `Le vendeur n'a pas assez de ${itemVendu.name} !`); return } @@ -3675,7 +3674,7 @@ export class RdDActor extends RdDBaseActor { ChatUtility.notifyUser(achat.userId, 'warn', `Vous n'avez pas assez d'argent pour payer ${Math.ceil(cout / 100)} sols !`); return; } - await this.decrementerVente(service, vendeur, itemVendu, quantite, cout); + await this.decrementerVente(vendeur, itemVendu, quantite, cout); if (acheteur) { await acheteur.depenserSols(cout); let createdItemId = await acheteur.creerQuantiteItem(vente.item, quantite); @@ -3697,7 +3696,7 @@ export class RdDActor extends RdDBaseActor { if (vente.quantiteNbLots <= achat.choix.nombreLots) { ChatUtility.removeChatMessageId(achat.chatMessageIdVente); } - else if (!service) { + else { vente["properties"] = itemVendu.getProprietes(); vente.quantiteNbLots -= achat.choix.nombreLots; vente.jsondata = JSON.stringify(vente.item); @@ -3708,18 +3707,15 @@ export class RdDActor extends RdDBaseActor { } } - async decrementerVente(service, vendeur, itemVendu, quantite, cout) { - if (service) { - await service.venteRefItem(itemVendu, quantite, cout) - } - else if (vendeur) { + async decrementerVente(vendeur, itemVendu, quantite, cout) { + if (vendeur) { await vendeur.ajouterSols(cout); await vendeur.decrementerQuantiteItem(itemVendu, quantite); } } - verifierQuantite(service, serviceSubItem, vendeur, item, quantiteTotal) { - const disponible = service ? service.getQuantiteDisponible(serviceSubItem, quantiteTotal) : (vendeur ? (item?.getQuantite() ?? 0) : quantiteTotal); + verifierQuantite(vendeur, item, quantiteTotal) { + const disponible = vendeur ? (item?.getQuantite() ?? 0) : quantiteTotal; return disponible >= quantiteTotal; } diff --git a/module/actor/base-actor-sheet.js b/module/actor/base-actor-sheet.js index 30dcf9a7..7ffa9259 100644 --- a/module/actor/base-actor-sheet.js +++ b/module/actor/base-actor-sheet.js @@ -153,7 +153,7 @@ export class RdDBaseActorSheet extends ActorSheet { RdDSheetUtility.splitItem(item, this.actor); }); this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, RdDSheetUtility.getItem(event, this.actor))); - this.html.find('.item-vendre').click(async event => RdDSheetUtility.getItem(event, this.actor)?.proposerVente()); + this.html.find('.item-vendre').click(async event => RdDSheetUtility.getItem(event, this.actor)?.proposerVente(this.getQuantiteMax(item))); this.html.find('.creer-un-objet').click(async event => { this.selectObjetTypeToCreate(); @@ -170,7 +170,10 @@ export class RdDBaseActorSheet extends ActorSheet { } - + getQuantiteMax(item) { + return item.system.quantite; + } + /* -------------------------------------------- */ _getHeaderButtons() { let buttons = super._getHeaderButtons(); diff --git a/module/dialog-item-achat.js b/module/dialog-item-achat.js index 12648644..e43ea5d8 100644 --- a/module/dialog-item-achat.js +++ b/module/dialog-item-achat.js @@ -30,15 +30,13 @@ export class DialogItemAchat extends Dialog { } - static async onAcheter({ item, vendeur, acheteur, service, serviceSubItem, tailleLot, prixLot, nbLots, quantiteIllimite, chatMessageIdVente }) { + static async onAcheter({ item, vendeur, acheteur, tailleLot, prixLot, nbLots, quantiteIllimite, chatMessageIdVente }) { const venteData = { item, actingUserId: game.user.id, vendeurId: vendeur?.id, vendeur, acheteur, - serviceSubItem: serviceSubItem, - service, tailleLot, quantiteIllimite, quantiteNbLots: nbLots, @@ -77,7 +75,7 @@ export class DialogItemAchat extends Dialog { buttons[actionAchat] = { label: actionAchat, callback: it => { this.onAchat(); } }; buttons["decliner"] = { label: "Décliner", callback: it => { } }; const acheteur = venteData.acheteur?.name ?? 'Un acheteur'; - const vendeur = (venteData.service ?? venteData.vendeur)?.name ?? 'Un vendeur'; + const vendeur = venteData.vendeur?.name ?? 'Un vendeur'; let conf = { title: `${acheteur} - ${actionAchat} à ${vendeur}`, content: html, @@ -93,7 +91,6 @@ export class DialogItemAchat extends Dialog { await this.html.find(".nombreLots").change(); (this.venteData.vendeur ?? this.venteData.acheteur).achatVente({ userId: game.user.id, - serviceId: this.venteData.service?.id, vendeurId: this.venteData.vendeur?.id, acheteurId: this.venteData.acheteur?.id, prixTotal: this.venteData.prixTotal, diff --git a/module/dialog-item-vente.js b/module/dialog-item-vente.js index f0e7055c..a027ef61 100644 --- a/module/dialog-item-vente.js +++ b/module/dialog-item-vente.js @@ -2,15 +2,13 @@ import { HtmlUtility } from "./html-utility.js"; export class DialogItemVente extends Dialog { - static async display({ item, callback, service = undefined, quantiteMax = undefined }) { - const quantite = quantiteMax ?? item.getQuantite(); + static async display({ item, callback, quantiteMax = undefined }) { + const quantite = quantiteMax ?? item.getQuantite() ?? 1; const isOwned = item.isOwned; - // const isOwned = item.isOwned || service?.actor; const venteData = { item: item, - alias: item.actor?.name ?? service?.name ?? game.user.name, - serviceId: service?.id, - vendeurId: item.actor?.id ?? service?.actor?.id, + alias: item.actor?.name ?? game.user.name, + vendeurId: item.actor?.id , prixOrigine: item.system.cout, prixUnitaire: item.system.cout, prixLot: item.system.cout, @@ -18,7 +16,7 @@ export class DialogItemVente extends Dialog { quantiteNbLots: quantite, quantiteMaxLots: quantite, quantiteMax: quantite, - quantiteIllimite: (service && service.system && service.system.illimite) ? service.system.illimite : !isOwned, + quantiteIllimite: !isOwned || quantiteMax == undefined, isOwned: isOwned, }; const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.html`, venteData); diff --git a/module/item-service.js b/module/item-service.js index bc00ded4..58582a43 100644 --- a/module/item-service.js +++ b/module/item-service.js @@ -47,7 +47,7 @@ export class RdDItemService extends RdDItem { async vendre(subItem) { const item = await RdDItem.getCorrespondingItem(subItem); const quantiteMax = this.system.illimite ? undefined : subItem.system.quantite; - await item.proposerVente({ service: this, quantiteMax }); + await item.proposerVente(quantiteMax); } async acheter(acheteur, subItem) { diff --git a/module/item-sheet.js b/module/item-sheet.js index 2eb610a0..b803de32 100644 --- a/module/item-sheet.js +++ b/module/item-sheet.js @@ -60,7 +60,7 @@ export class RdDItemSheet extends ItemSheet { buttons.unshift({ class: "vendre", icon: "fas fa-comments-dollar", - onclick: ev => this.item.proposerVente({service: this, quantiteMax: 1}) + onclick: ev => this.item.proposerVente(1) }); } buttons.unshift({ diff --git a/module/item.js b/module/item.js index 8455a733..4deec4a1 100644 --- a/module/item.js +++ b/module/item.js @@ -420,7 +420,7 @@ export class RdDItem extends Item { return [true, undefined]; } - async proposerVente({ service = undefined, quantiteMax = undefined }) { + async proposerVente(quantiteMax = undefined) { console.log(this); if (this.isConteneurNonVide()) { ui.notifications.warn(`Votre ${this.name} n'est pas vide, pas possible de le proposer`); @@ -428,7 +428,6 @@ export class RdDItem extends Item { } await DialogItemVente.display({ item: this, - service: service, quantiteMax, callback: async (vente) => { vente["properties"] = this.getProprietes(); diff --git a/templates/dialog-item-achat.html b/templates/dialog-item-achat.html index 6bdff205..03b83a2d 100644 --- a/templates/dialog-item-achat.html +++ b/templates/dialog-item-achat.html @@ -2,9 +2,7 @@
      - {{#if service}} - {{service.name}} - {{else if vendeur}} + {{#if vendeur}} {{vendeur.name}} {{else}} Vendeur MJ -- 2.35.3 From 92388df5c79053764de5a378822dd02b2636816a Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 1 Jan 2023 22:10:03 +0100 Subject: [PATCH 07/18] =?UTF-8?q?d=C3=A9placement=20gestion=20equipement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Déplacement de la gestion d'équipement dans base-actor --- module/actor-sheet.js | 7 +- module/actor.js | 449 +----------------------------- module/actor/base-actor-sheet.js | 35 ++- module/actor/base-actor.js | 453 ++++++++++++++++++++++++++++++- module/rdd-main.js | 2 +- module/rdd-namegen.js | 4 +- templates/actor-sheet.html | 2 +- 7 files changed, 483 insertions(+), 469 deletions(-) diff --git a/module/actor-sheet.js b/module/actor-sheet.js index b735fda4..803ad71c 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -10,7 +10,6 @@ import { DialogSplitItem } from "./dialog-split-item.js"; import { ReglesOptionelles } from "./settings/regles-optionelles.js"; import { RdDSheetUtility } from "./rdd-sheet-utility.js"; import { STATUSES } from "./settings/status-effects.js"; -import { Monnaie } from "./item-monnaie.js"; import { MAINS_DIRECTRICES } from "./actor.js"; import { RdDBaseActorSheet } from "./actor/base-actor-sheet.js"; import { RdDItem } from "./item.js"; @@ -46,10 +45,8 @@ export class RdDActorSheet extends RdDBaseActorSheet { effects: this.actor.effects.map(e => foundry.utils.deepClone(e)), limited: this.actor.limited, owner: this.actor.isOwner, - description: await TextEditor.enrichHTML(this.object.system.description, { async: true }), - biographie: await TextEditor.enrichHTML(this.object.system.biographie, { async: true }), - notes: await TextEditor.enrichHTML(this.object.system.notes, { async: true }), - notesmj: await TextEditor.enrichHTML(this.object.system.notesmj, { async: true }), + biographie: await TextEditor.enrichHTML(this.actor.system.biographie, { async: true }), + notes: await TextEditor.enrichHTML(this.actor.system.notes, { async: true }), }); mergeObject(formData.calc, { surenc: this.actor.computeMalusSurEncombrement(), diff --git a/module/actor.js b/module/actor.js index 8b85cdce..dca482fb 100644 --- a/module/actor.js +++ b/module/actor.js @@ -13,7 +13,6 @@ import { RdDItemSort } from "./item-sort.js"; import { Grammar } from "./grammar.js"; import { RdDEncaisser } from "./rdd-roll-encaisser.js"; import { RdDCombat } from "./rdd-combat.js"; -import { RdDAudio } from "./rdd-audio.js"; import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemArme } from "./item-arme.js"; import { RdDAlchimie } from "./rdd-alchimie.js"; @@ -24,13 +23,11 @@ import { ReglesOptionelles } from "./settings/regles-optionelles.js"; import { EffetsDraconiques } from "./tmr/effets-draconiques.js"; import { Draconique } from "./tmr/draconique.js"; import { RdDCarac } from "./rdd-carac.js"; -import { Monnaie } from "./item-monnaie.js"; import { DialogConsommer } from "./dialog-item-consommer.js"; import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js"; import { RollDataAjustements } from "./rolldata-ajustements.js"; -import { RdDItem } from "./item.js"; import { RdDPossession } from "./rdd-possession.js"; -import { ENTITE_BLURETTE, ENTITE_INCARNE, ENTITE_NONINCARNE, HIDE_DICE, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; +import { ENTITE_BLURETTE, ENTITE_INCARNE, ENTITE_NONINCARNE, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; import { RdDConfirm } from "./rdd-confirm.js"; import { DialogValidationEncaissement } from "./dialog-validation-encaissement.js"; import { RdDRencontre } from "./item-rencontre.js"; @@ -77,12 +74,12 @@ export class RdDActor extends RdDBaseActor { /* -------------------------------------------- */ _prepareCreatureData(actorData) { - this.computeEncombrementTotalEtMalusArmure(); + this.computeEncTotal(); } /* -------------------------------------------- */ _prepareVehiculeData(actorData) { - this.computeEncombrementTotalEtMalusArmure(); + this.computeEncTotal(); } /* -------------------------------------------- */ @@ -94,7 +91,8 @@ export class RdDActor extends RdDBaseActor { RdDCarac.computeCarac(actorData.system) this.computeIsHautRevant(); await this.cleanupConteneurs(); - await this.computeEncombrementTotalEtMalusArmure(); + await this.computeEncTotal(); + await this.computeMalusArmure(); } /* -------------------------------------------- */ @@ -234,10 +232,6 @@ export class RdDActor extends RdDBaseActor { } /* -------------------------------------------- */ - getMonnaie(id) { - return this.findItemLike(id, 'monnaie'); - } - getTache(id) { return this.findItemLike(id, 'tache'); } @@ -993,237 +987,7 @@ export class RdDActor extends RdDBaseActor { await this.update({ [`system.attributs.${fieldName}.value`]: fieldValue }); } - /* -------------------------------------------- */ - _isConteneurContenu(item, conteneur) { - if (item?.isConteneur()) { // Si c'est un conteneur, il faut vérifier qu'on ne le déplace pas vers un sous-conteneur lui appartenant - for (let id of item.system.contenu) { - let subObjet = this.getItem(id); - if (subObjet?.id == conteneur.id) { - return true; // Loop detected ! - } - if (subObjet?.isConteneur()) { - return this._isConteneurContenu(subObjet, conteneur); - } - } - } - return false; - } - /* -------------------------------------------- */ - getRecursiveEnc(objet) { - if (!objet) { - return 0; - } - const tplData = objet.system; - if (objet.type != 'conteneur') { - return Number(tplData.encombrement) * Number(tplData.quantite); - } - const encContenus = tplData.contenu.map(idContenu => this.getRecursiveEnc(this.getItem(idContenu))); - return encContenus.reduce(Misc.sum(), 0) - + Number(tplData.encombrement) /* TODO? Number(tplData.quantite) -- on pourrait avoir plusieurs conteneurs...*/ - } - - /* -------------------------------------------- */ - buildSubConteneurObjetList(conteneurId, deleteList) { - let conteneur = this.getItem(conteneurId); - if (conteneur?.type == 'conteneur') { // Si c'est un conteneur - for (let subId of conteneur.system.contenu) { - let subObj = this.getItem(subId); - if (subObj) { - if (subObj.type == 'conteneur') { - this.buildSubConteneurObjetList(subId, deleteList); - } - deleteList.push({ id: subId, conteneurId: conteneurId }); - } - } - } - } - - /* -------------------------------------------- */ - async deleteAllConteneur(itemId, options) { - let list = []; - list.push({ id: itemId, conteneurId: undefined }); // Init list - this.buildSubConteneurObjetList(itemId, list); - await this.deleteEmbeddedDocuments('Item', list.map(it => it.id), options); - } - - /* -------------------------------------------- */ - /** Supprime un item d'un conteneur, sur la base - * de leurs ID */ - async enleverDeConteneur(item, conteneur, onEnleverDeConteneur) { - if (conteneur?.isConteneur()) { - item.estContenu = false; - await this.updateEmbeddedDocuments('Item', [{ - _id: conteneur.id, - 'system.contenu': conteneur.system.contenu.filter(id => id != item.id) - }]); - onEnleverDeConteneur(); - } - } - - /* -------------------------------------------- */ - /** Ajoute un item dans un conteneur, sur la base - * de leurs ID */ - async ajouterDansConteneur(item, conteneur, onAjouterDansConteneur) { - if (!conteneur) { - // TODO: afficher - item.estContenu = false; - } - else if (conteneur.isConteneur()) { - item.estContenu = true; - await this.updateEmbeddedDocuments('Item', [{ - _id: conteneur.id, - 'system.contenu': [...conteneur.system.contenu, item.id] - }]); - onAjouterDansConteneur(item.id, conteneur.id); - } - } - - /* -------------------------------------------- */ - /** Fonction de remise à plat de l'équipement (ie vide les champs 'contenu') */ - async nettoyerConteneurs() { - RdDConfirm.confirmer({ - settingConfirmer: "confirmation-vider", - content: `

      Etes vous certain de vouloir vider tous les conteneurs ?

      `, - title: 'Vider les conteneurs', - buttonLabel: 'Vider', - onAction: async () => { - const corrections = []; - for (let item of this.items) { - if (item.estContenu) { - item.estContenu = undefined; - } - if (item.type == 'conteneur' && item.system.contenu.length > 0) { - corrections.push({ _id: item.id, 'system.contenu': [] }); - } - } - if (corrections.length > 0) { - await this.updateEmbeddedDocuments('Item', corrections); - } - } - }); - } - - async processDropItem(params) { - const targetActorId = this.id; - const sourceActorId = params.sourceActorId; - const itemId = params.itemId; - const destId = params.destId; - const srcId = params.srcId; - if (sourceActorId && sourceActorId != targetActorId) { - console.log("Moving objects", sourceActorId, targetActorId, itemId); - this.moveItemsBetweenActors(itemId, sourceActorId); - return false; - } - let result = true; - const item = this.getItem(itemId); - if (item?.isInventaire() && sourceActorId == targetActorId) { - // rangement - if (srcId != destId && itemId != destId) { // déplacement de l'objet - const src = this.getItem(srcId); - const dest = this.getItem(destId); - const cible = this.getContenantOrParent(dest); - const [empilable, message] = item.isInventaireEmpilable(dest); - if (empilable) { - await dest.empiler(item) - result = false; - } - // changer de conteneur - else if (!cible || this.conteneurPeutContenir(cible, item)) { - await this.enleverDeConteneur(item, src, params.onEnleverConteneur); - await this.ajouterDansConteneur(item, cible, params.onAjouterDansConteneur); - if (message && !dest.isConteneur()) { - ui.notifications.info(cible - ? `${message}
      ${item.name} a été déplacé dans: ${cible.name}` - : `${message}
      ${item.name} a été sorti du conteneur`); - } - } - } - } - await this.computeEncombrementTotalEtMalusArmure(); - return result; - } - - getContenantOrParent(dest) { - if (!dest || dest.isConteneur()) { - return dest; - } - return this.getContenant(dest); - } - - getContenant(item) { - return this.itemTypes['conteneur'].find(it => it.system.contenu.includes(item.id)); - } - - /* -------------------------------------------- */ - conteneurPeutContenir(dest, item) { - if (!dest) { - return true; - } - if (!dest.isConteneur()) { - return false; - } - const destData = dest - if (this._isConteneurContenu(item, dest)) { - ui.notifications.warn(`Impossible de déplacer un conteneur parent (${item.name}) dans un de ses contenus ${destData.name} !`); - return false; // Loop detected ! - } - - // Calculer le total actuel des contenus - let encContenu = this.getRecursiveEnc(dest) - Number(destData.system.encombrement); - let newEnc = this.getRecursiveEnc(item); // Calculer le total actuel du nouvel objet - - // Teste si le conteneur de destination a suffisament de capacité pour recevoir le nouvel objet - if (Number(destData.system.capacite) < encContenu + newEnc) { - ui.notifications.warn( - `Le conteneur ${dest.name} a une capacité de ${destData.system.capacite}, et contient déjà ${encContenu}. - Impossible d'y ranger: ${item.name} d'encombrement ${newEnc}!`); - return false; - } - return true; - - } - - /* -------------------------------------------- */ - async moveItemsBetweenActors(itemId, sourceActorId) { - let itemsList = [] - let sourceActor = game.actors.get(sourceActorId); - itemsList.push({ id: itemId, conteneurId: undefined }); // Init list - sourceActor.buildSubConteneurObjetList(itemId, itemsList); // Get itemId list - - const itemsDataToCreate = itemsList.map(it => sourceActor.getItem(it.id)) - .map(it => duplicate(it)) - .map(it => { it.system.contenu = []; return it; }); - let newItems = await this.createEmbeddedDocuments('Item', itemsDataToCreate); - - let itemMap = this._buildMapOldNewId(itemsList, newItems); - - for (let item of itemsList) { // Second boucle pour traiter la remise en conteneurs - // gestion conteneur/contenu - if (item.conteneurId) { // l'Objet était dans un conteneur - let newConteneurId = itemMap[item.conteneurId]; // Get conteneur - let newConteneur = this.getItem(newConteneurId); - - let newItemId = itemMap[item.id]; // Get newItem - - console.log('New conteneur filling!', newConteneur, newItemId, item); - let contenu = duplicate(newConteneur.system.contenu); - contenu.push(newItemId); - await this.updateEmbeddedDocuments('Item', [{ _id: newConteneurId, 'system.contenu': contenu }]); - } - } - for (let item of itemsList) { - await sourceActor.deleteEmbeddedDocuments('Item', [item.id]); - } - } - - _buildMapOldNewId(itemsList, newItems) { - let itemMap = {}; - for (let i = 0; i < itemsList.length; i++) { - itemMap[itemsList[i].id] = newItems[i].id; // Pour garder le lien ancien / nouveau - } - return itemMap; - } isSurenc() { return this.isPersonnage() ? (this.computeMalusSurEncombrement() < 0) : false @@ -1268,16 +1032,6 @@ export class RdDActor extends RdDBaseActor { return this.listItems(type).find(it => Grammar.toLowerCaseNoAccent(it.name) == name); } - /* -------------------------------------------- */ - async computeEncombrementTotalEtMalusArmure() { - if (!this.pack) { - await this.computeMalusArmure(); - this.encTotal = this.items.map(it => it.getEncTotal()).reduce(Misc.sum(), 0); - return this.encTotal; - } - return 0; - } - /* -------------------------------------------- */ async computeMalusArmure() { if (this.isPersonnage()) { @@ -1291,15 +1045,6 @@ export class RdDActor extends RdDBaseActor { } } - /* -------------------------------------------- */ - computePrixTotalEquipement() { - const valeur = this.items.filter(it => it.isInventaire()) - .filter(it => !it.isMonnaie()) - .map(it => it.valeurTotale()) - .reduce(Misc.sum(), 0); - return valeur; - } - /* -------------------------------------------- */ computeResumeBlessure(blessures = undefined) { blessures = blessures ?? this.system.blessures; @@ -1332,7 +1077,7 @@ export class RdDActor extends RdDBaseActor { } } - recompute(){ + recompute() { this.computeEtatGeneral(); } @@ -3282,7 +3027,7 @@ export class RdDActor extends RdDBaseActor { if (item && ['arme', 'armure'].includes(item.type)) { const isEquipe = !item.system.equipe; await this.updateEmbeddedDocuments('Item', [{ _id: item.id, "system.equipe": isEquipe }]); - this.computeEncombrementTotalEtMalusArmure(); // Mise à jour encombrement + this.computeEncTotal(); // Mise à jour encombrement if (isEquipe) this.verifierForceMin(item); } @@ -3575,186 +3320,6 @@ export class RdDActor extends RdDBaseActor { return; } - /* -------------------------------------------- */ - async payerSols(depense) { - depense = Number(depense); - if (depense == 0) { - return; - } - let fortune = super.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 = { - whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), - content: msg - }; - ChatMessage.create(message); - } - - async depenserSols(sols) { - let reste = super.getFortune() - Number(sols); - if (reste >= 0) { - await Monnaie.optimiserFortune(this, reste); - } - return reste; - } - - async ajouterSols(sols, fromActorId = undefined) { - sols = Number(sols); - if (sols == 0) { - return; - } - if (sols < 0) { - ui.notifications.error(`Impossible d'ajouter un gain de ${sols} <0`); - return; - } - if (fromActorId && !game.user.isGM) { - RdDBaseActor.remoteActorCall({ - userId: Misc.connectedGMOrUser(), - actorId: this.id, - method: 'ajouterSols', args: [sols, fromActorId] - }); - } - else { - const fromActor = game.actors.get(fromActorId) - await Monnaie.optimiserFortune(this, sols + this.getFortune()); - - RdDAudio.PlayContextAudio("argent"); // Petit son - ChatMessage.create({ - whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), - content: `Vous avez reçu ${sols} Sols ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.` - }); - } - } - - /* -------------------------------------------- */ - async monnaieIncDec(id, value) { - let monnaie = this.getMonnaie(id); - if (monnaie) { - const quantite = Math.max(0, monnaie.system.quantite + value); - await this.updateEmbeddedDocuments('Item', [{ _id: monnaie.id, 'system.quantite': quantite }]); - } - } - - /* -------------------------------------------- */ - async achatVente(achat) { - if (achat.vendeurId == achat.acheteurId) { - ui.notifications.info("Inutile de se vendre à soi-même"); - return; - } - if (!Misc.isUniqueConnectedGM()) { - RdDBaseActor.remoteActorCall({ - actorId: achat.vendeurId ?? achat.acheteurId, - method: 'achatVente', - args: [achat] - }); - return; - } - - const cout = Number(achat.prixTotal ?? 0); - const vendeur = achat.vendeurId ? game.actors.get(achat.vendeurId) : undefined; - const acheteur = achat.acheteurId ? game.actors.get(achat.acheteurId) : undefined; - const vente = achat.vente; - const quantite = (achat.choix.nombreLots ?? 1) * (vente.tailleLot); - const itemVendu = vendeur?.getItem(vente.item._id) ?? (await RdDItem.getCorrespondingItem(vente.item)); - if (!this.verifierQuantite(vendeur, itemVendu, quantite)) { - ChatUtility.notifyUser(achat.userId, 'warn', `Le vendeur n'a pas assez de ${itemVendu.name} !`); - return - } - - if ((acheteur?.getFortune() ?? 0) < Number(cout)) { - ChatUtility.notifyUser(achat.userId, 'warn', `Vous n'avez pas assez d'argent pour payer ${Math.ceil(cout / 100)} sols !`); - return; - } - await this.decrementerVente(vendeur, itemVendu, quantite, cout); - if (acheteur) { - await acheteur.depenserSols(cout); - let createdItemId = await acheteur.creerQuantiteItem(vente.item, quantite); - await acheteur.consommerNourritureAchetee(achat, vente, createdItemId); - } - if (cout > 0) { - RdDAudio.PlayContextAudio("argent"); - } - const chatAchatItem = duplicate(vente); - chatAchatItem.quantiteTotal = quantite; - ChatMessage.create({ - user: achat.userId, - speaker: { alias: (acheteur ?? vendeur).name }, - whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), - content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-achat-item.html', chatAchatItem) - }); - - if (!vente.quantiteIllimite) { - if (vente.quantiteNbLots <= achat.choix.nombreLots) { - ChatUtility.removeChatMessageId(achat.chatMessageIdVente); - } - else { - vente["properties"] = itemVendu.getProprietes(); - vente.quantiteNbLots -= achat.choix.nombreLots; - vente.jsondata = JSON.stringify(vente.item); - const messageVente = game.messages.get(achat.chatMessageIdVente); - messageVente.update({ content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente) }); - messageVente.render(true); - } - } - } - - async decrementerVente(vendeur, itemVendu, quantite, cout) { - if (vendeur) { - await vendeur.ajouterSols(cout); - await vendeur.decrementerQuantiteItem(itemVendu, quantite); - } - } - - verifierQuantite(vendeur, item, quantiteTotal) { - const disponible = vendeur ? (item?.getQuantite() ?? 0) : quantiteTotal; - return disponible >= quantiteTotal; - } - - async consommerNourritureAchetee(achat, vente, createdItemId) { - if (achat.choix.consommer && vente.item.type == 'nourritureboisson' && createdItemId != undefined) { - achat.choix.doses = achat.choix.nombreLots; - await this.consommerNourritureboisson(createdItemId, achat.choix, vente.actingUserId); - } - } - - async decrementerQuantiteItem(item, quantite) { - let resteQuantite = (item.system.quantite ?? 1) - quantite; - if (resteQuantite <= 0) { - await this.deleteEmbeddedDocuments("Item", [item.id]); - if (resteQuantite < 0) { - ui.notifications.warn(`La quantité de ${item.name} était insuffisante, l'objet a donc été supprimé`) - } - } - else if (resteQuantite > 0) { - await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': resteQuantite }]); - } - } - - async creerQuantiteItem(item, quantite) { - const items = await this.createEmbeddedDocuments("Item", RdDActor.$prepareListeAchat(item, quantite)); - return items.length > 0 ? items[0].id : undefined; - } - - static $prepareListeAchat(item, quantite) { - const isItemEmpilable = "quantite" in item.system; - const achatData = { - type: item.type, - img: item.img, - name: item.name, - system: mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined }), - }; - return isItemEmpilable ? [achatData] : Array.from({ length: quantite }, (_, i) => achatData); - } - /* -------------------------------------------- */ async effectuerTacheAlchimie(recetteId, tacheAlchimie, texteTache) { let recetteData = this.findItemLike(recetteId, 'recettealchimique'); diff --git a/module/actor/base-actor-sheet.js b/module/actor/base-actor-sheet.js index 7ffa9259..328e2b72 100644 --- a/module/actor/base-actor-sheet.js +++ b/module/actor/base-actor-sheet.js @@ -40,6 +40,7 @@ export class RdDBaseActorSheet extends ActorSheet { isLimited: userRightLevel >= CONST.DOCUMENT_OWNERSHIP_LEVELS.LIMITED, isObserver: userRightLevel >= CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER, isOwner: userRightLevel >= CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER, + owner: this.actor.isOwner, }); let formData = { @@ -49,13 +50,15 @@ export class RdDBaseActorSheet extends ActorSheet { img: this.actor.img, name: this.actor.name, system: foundry.utils.deepClone(this.actor.system), + description: await TextEditor.enrichHTML(this.actor.system.description, { async: true }), + notesmj: await TextEditor.enrichHTML(this.actor.system.notesmj, { async: true }), options: options, } this.filterItemsPerTypeForSheet(formData, this.actor.itemTypes); formData.calc = { fortune: this.toSolsDeniers(this.actor.getFortune()), prixTotalEquipement: this.actor.computePrixTotalEquipement(), - encTotal: await this.actor.computeEncombrementTotalEtMalusArmure(), + encTotal: await this.actor.computeEncTotal(), } this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets); @@ -138,22 +141,22 @@ export class RdDBaseActorSheet extends ActorSheet { this.html = html; this.html.find('.conteneur-name a').click(async event => { - RdDUtility.toggleAfficheContenu(RdDSheetUtility.getItemId(event)); + RdDUtility.toggleAfficheContenu(this.getItemId(event)); this.render(true); }); - this.html.find('.item-edit').click(async event => RdDSheetUtility.getItem(event, this.actor)?.sheet.render(true)) - this.html.find('.item-montrer').click(async event => RdDSheetUtility.getItem(event, this.actor)?.postItemToChat()); + this.html.find('.item-edit').click(async event => this.getItem(event)?.sheet.render(true)) + this.html.find('.item-montrer').click(async event => this.getItem(event)?.postItemToChat()); this.html.find('.actor-montrer').click(async event => this.actor.postActorToChat()); // Everything below here is only needed if the sheet is editable if (!this.options.editable) return; this.html.find('.item-split').click(async event => { - const item = RdDSheetUtility.getItem(event, this.actor); + const item = this.getItem(event); RdDSheetUtility.splitItem(item, this.actor); }); - this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, RdDSheetUtility.getItem(event, this.actor))); - this.html.find('.item-vendre').click(async event => RdDSheetUtility.getItem(event, this.actor)?.proposerVente(this.getQuantiteMax(item))); + this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, this.getItem(event))); + this.html.find('.item-vendre').click(async event => this.vendre(this.getItem(event))); this.html.find('.creer-un-objet').click(async event => { this.selectObjetTypeToCreate(); @@ -162,16 +165,19 @@ export class RdDBaseActorSheet extends ActorSheet { this.actor.nettoyerConteneurs(); }); this.html.find('.monnaie-plus').click(async event => { - this.actor.monnaieIncDec(RdDSheetUtility.getItemId(event), 1); + this.actor.monnaieIncDec(this.getItemId(event), 1); }); this.html.find('.monnaie-moins').click(async event => { - this.actor.monnaieIncDec(RdDSheetUtility.getItemId(event), -1); + this.actor.monnaieIncDec(this.getItemId(event), -1); }); - } - getQuantiteMax(item) { - return item.system.quantite; + getItemId(event) { + return RdDSheetUtility.getItemId(event); + } + + getItem(event) { + return RdDSheetUtility.getItem(event, this.actor); } /* -------------------------------------------- */ @@ -197,7 +203,6 @@ export class RdDBaseActorSheet extends ActorSheet { } } - /* -------------------------------------------- */ async selectObjetTypeToCreate() { let typeObjets = RdDItem.getItemTypesInventaire(); @@ -256,4 +261,8 @@ export class RdDBaseActorSheet extends ActorSheet { } } + vendre(item) { + item?.proposerVente(this.actor.getQuantiteDisponible(item)); + } + } diff --git a/module/actor/base-actor.js b/module/actor/base-actor.js index b95a7ff5..409cd793 100644 --- a/module/actor/base-actor.js +++ b/module/actor/base-actor.js @@ -1,6 +1,9 @@ +import { ChatUtility } from "../chat-utility.js"; import { SYSTEM_SOCKET_ID } from "../constants.js"; import { Monnaie } from "../item-monnaie.js"; +import { RdDItem } from "../item.js"; import { Misc } from "../misc.js"; +import { RdDAudio } from "../rdd-audio.js"; import { RdDUtility } from "../rdd-utility.js"; import { SystemCompendiums } from "../settings/system-compendiums.js"; @@ -73,14 +76,14 @@ export class RdDBaseActor extends Actor { if (actorData.items) { return await super.create(actorData, options); } - + actorData.items = []; if (actorData.type == "personnage") { const competences = await SystemCompendiums.getCompetences(actorData.type); - actorData.items = competences.map(i => i.toObject()) + actorData.items = actorData.items.concat(competences.map(i => i.toObject())) .concat(Monnaie.monnaiesStandard()); } - else { - actorData.items = []; + else if (actorData.type == "commerce") { + actorData.items = actorData.items.concat(Monnaie.monnaiesStandard()); } return super.create(actorData, options); } @@ -120,9 +123,11 @@ export class RdDBaseActor extends Actor { ?? Misc.findFirstLike(idOrName, this.listItems(type), { description: Misc.typeName('Item', type) }); } + getMonnaie(id) { return this.findItemLike(id, 'monnaie'); } recompute() { } + /* -------------------------------------------- */ async onPreUpdateItem(item, change, options, id) { } @@ -132,11 +137,218 @@ export class RdDBaseActor extends Actor { async onUpdateActor(update, options, actorId) { } - + /* -------------------------------------------- */ getFortune() { return Monnaie.getFortune(this.itemTypes['monnaie']); } + /* -------------------------------------------- */ + async monnaieIncDec(id, value) { + let monnaie = this.getMonnaie(id); + if (monnaie) { + const quantite = Math.max(0, monnaie.system.quantite + value); + await this.updateEmbeddedDocuments('Item', [{ _id: monnaie.id, 'system.quantite': quantite }]); + } + } + + computePrixTotalEquipement() { + return this.items.filter(it => it.isInventaire()) + .filter(it => !it.isMonnaie()) + .map(it => it.valeurTotale()) + .reduce(Misc.sum(), 0); + } + + async payerSols(depense) { + depense = Number(depense); + if (depense == 0) { + return; + } + 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 = { + whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), + content: msg + }; + ChatMessage.create(message); + } + + async depenserSols(sols) { + let reste = this.getFortune() - Number(sols); + if (reste >= 0) { + await Monnaie.optimiserFortune(this, reste); + } + return reste; + } + + async ajouterSols(sols, fromActorId = undefined) { + sols = Number(sols); + if (sols == 0) { + return; + } + if (sols < 0) { + ui.notifications.error(`Impossible d'ajouter un gain de ${sols} <0`); + return; + } + if (fromActorId && !game.user.isGM) { + RdDBaseActor.remoteActorCall({ + userId: Misc.connectedGMOrUser(), + actorId: this.id, + method: 'ajouterSols', args: [sols, fromActorId] + }); + } + else { + const fromActor = game.actors.get(fromActorId) + await Monnaie.optimiserFortune(this, sols + this.getFortune()); + + RdDAudio.PlayContextAudio("argent"); // Petit son + ChatMessage.create({ + whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), + content: `Vous avez reçu ${sols} Sols ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.` + }); + } + } + + /* -------------------------------------------- */ + + getQuantiteDisponible(item) { + return item?.getQuantite(); + } + + /* -------------------------------------------- */ + async achatVente(achat) { + if (achat.vendeurId == achat.acheteurId) { + ui.notifications.info("Inutile de se vendre à soi-même"); + return; + } + if (!Misc.isUniqueConnectedGM()) { + RdDBaseActor.remoteActorCall({ + actorId: achat.vendeurId ?? achat.acheteurId, + method: 'achatVente', + args: [achat] + }); + return; + } + + const cout = Number(achat.prixTotal ?? 0); + const vendeur = achat.vendeurId ? game.actors.get(achat.vendeurId) : undefined; + const acheteur = achat.acheteurId ? game.actors.get(achat.acheteurId) : undefined; + const vente = achat.vente; + const quantite = (achat.choix.nombreLots ?? 1) * (vente.tailleLot); + const itemVendu = vendeur?.getItem(vente.item._id); + if (!this.verifierQuantite(vendeur, itemVendu, quantite)) { + ChatUtility.notifyUser(achat.userId, 'warn', `Le vendeur n'a pas assez de ${itemVendu.name} !`); + return + } + if (acheteur && !acheteur.verifierFortune(cout)) { + ChatUtility.notifyUser(achat.userId, 'warn', `Vous n'avez pas assez d'argent pour payer ${Math.ceil(cout / 100)} sols !`); + return; + } + await this.decrementerVente(vendeur, itemVendu, quantite, cout); + if (acheteur) { + await acheteur.depenserSols(cout); + let createdItemId = await acheteur.creerQuantiteItem(vente.item, quantite); + await acheteur.consommerNourritureAchetee(achat, vente, createdItemId); + } + if (cout > 0) { + RdDAudio.PlayContextAudio("argent"); + } + const chatAchatItem = duplicate(vente); + chatAchatItem.quantiteTotal = quantite; + ChatMessage.create({ + user: achat.userId, + speaker: { alias: (acheteur ?? vendeur).name }, + whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), + content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-achat-item.html', chatAchatItem) + }); + + if (!vente.quantiteIllimite) { + if (vente.quantiteNbLots <= achat.choix.nombreLots) { + ChatUtility.removeChatMessageId(achat.chatMessageIdVente); + } + else if (achat.chatMessageIdVente) { + vente["properties"] = itemVendu.getProprietes(); + vente.quantiteNbLots -= achat.choix.nombreLots; + vente.jsondata = JSON.stringify(vente.item); + const messageVente = game.messages.get(achat.chatMessageIdVente); + messageVente.update({ content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente) }); + messageVente.render(true); + } + } + } + + async decrementerVente(vendeur, itemVendu, quantite, cout) { + if (vendeur) { + await vendeur.ajouterSols(cout); + await vendeur.decrementerQuantiteItem(itemVendu, quantite); + } + } + + verifierFortune(cout) { + return this.getFortune() >= cout; + } + + verifierQuantite(vendeur, item, quantiteTotal) { + const disponible = vendeur?.getQuantiteDisponible(item); + return disponible == undefined || disponible >= quantiteTotal; + } + + async consommerNourritureAchetee(achat, vente, createdItemId) { + if (achat.choix.consommer && vente.item.type == 'nourritureboisson' && createdItemId != undefined) { + achat.choix.doses = achat.choix.nombreLots; + await this.consommerNourritureboisson(createdItemId, achat.choix, vente.actingUserId); + } + } + + + async decrementerQuantiteItem(item, quantite, options={supprimerSiZero: true}) { + let resteQuantite = (item.system.quantite ?? 1) - quantite; + if (resteQuantite <= 0) { + if (options.supprimerSiZero) { + await this.deleteEmbeddedDocuments("Item", [item.id]); + } + else{ + await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': 0 }]); + } + if (resteQuantite < 0) { + ui.notifications.warn(`La quantité de ${item.name} était insuffisante, l'objet a donc été supprimé`) + } + } + else if (resteQuantite > 0) { + await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': resteQuantite }]); + } + } + + async creerQuantiteItem(item, quantite) { + const isItemEmpilable = "quantite" in item.system; + const baseItem = { + type: item.type, + img: item.img, + name: item.name, + system: mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined }) + }; + const newItems = isItemEmpilable ? [baseItem] : Array.from({ length: quantite }, (_, i) => baseItem); + const items = await this.createEmbeddedDocuments("Item", newItems); + return items.length > 0 ? items[0].id : undefined; + } + + /* -------------------------------------------- */ + async computeEncTotal() { + if (!this.pack) { + this.encTotal = this.items.map(it => it.getEncTotal()).reduce(Misc.sum(), 0); + return this.encTotal; + } + return 0; + } + async createItem(type, name = undefined) { if (!name) { name = 'Nouveau ' + Misc.typeName('Item', type); @@ -148,6 +360,237 @@ export class RdDBaseActor extends Actor { return false; } + async processDropItem(params) { + const targetActorId = this.id; + const sourceActorId = params.sourceActorId; + const itemId = params.itemId; + const destId = params.destId; + const srcId = params.srcId; + if (sourceActorId && sourceActorId != targetActorId) { + console.log("Moving objects", sourceActorId, targetActorId, itemId); + this.moveItemsBetweenActors(itemId, sourceActorId); + return false; + } + let result = true; + const item = this.getItem(itemId); + if (item?.isInventaire() && sourceActorId == targetActorId) { + // rangement + if (srcId != destId && itemId != destId) { // déplacement de l'objet + const src = this.getItem(srcId); + const dest = this.getItem(destId); + const cible = this.getContenantOrParent(dest); + const [empilable, message] = item.isInventaireEmpilable(dest); + if (empilable) { + await dest.empiler(item) + result = false; + } + // changer de conteneur + else if (!cible || this.conteneurPeutContenir(cible, item)) { + await this.enleverDeConteneur(item, src, params.onEnleverConteneur); + await this.ajouterDansConteneur(item, cible, params.onAjouterDansConteneur); + if (message && !dest.isConteneur()) { + ui.notifications.info(cible + ? `${message}
      ${item.name} a été déplacé dans: ${cible.name}` + : `${message}
      ${item.name} a été sorti du conteneur`); + } + } + } + } + await this.computeEncTotal(); + return result; + } + + getContenantOrParent(dest) { + if (!dest || dest.isConteneur()) { + return dest; + } + return this.getContenant(dest); + } + + getContenant(item) { + return this.itemTypes['conteneur'].find(it => it.system.contenu.includes(item.id)); + } + + + /* -------------------------------------------- */ + conteneurPeutContenir(dest, item) { + if (!dest) { + return true; + } + if (!dest.isConteneur()) { + return false; + } + const destData = dest + if (this._isConteneurContenu(item, dest)) { + ui.notifications.warn(`Impossible de déplacer un conteneur parent (${item.name}) dans un de ses contenus ${destData.name} !`); + return false; // Loop detected ! + } + + // Calculer le total actuel des contenus + let encContenu = this.getRecursiveEnc(dest) - Number(destData.system.encombrement); + let newEnc = this.getRecursiveEnc(item); // Calculer le total actuel du nouvel objet + + // Teste si le conteneur de destination a suffisament de capacité pour recevoir le nouvel objet + if (Number(destData.system.capacite) < encContenu + newEnc) { + ui.notifications.warn( + `Le conteneur ${dest.name} a une capacité de ${destData.system.capacite}, et contient déjà ${encContenu}. + Impossible d'y ranger: ${item.name} d'encombrement ${newEnc}!`); + return false; + } + return true; + } + + /* -------------------------------------------- */ + _isConteneurContenu(item, conteneur) { + if (item?.isConteneur()) { // Si c'est un conteneur, il faut vérifier qu'on ne le déplace pas vers un sous-conteneur lui appartenant + for (let id of item.system.contenu) { + let subObjet = this.getItem(id); + if (subObjet?.id == conteneur.id) { + return true; // Loop detected ! + } + if (subObjet?.isConteneur()) { + return this._isConteneurContenu(subObjet, conteneur); + } + } + } + return false; + } + /* -------------------------------------------- */ + getRecursiveEnc(objet) { + if (!objet) { + return 0; + } + const tplData = objet.system; + if (objet.type != 'conteneur') { + return Number(tplData.encombrement) * Number(tplData.quantite); + } + const encContenus = tplData.contenu.map(idContenu => this.getRecursiveEnc(this.getItem(idContenu))); + return encContenus.reduce(Misc.sum(), 0) + + Number(tplData.encombrement) /* TODO? Number(tplData.quantite) -- on pourrait avoir plusieurs conteneurs...*/ + } + + /* -------------------------------------------- */ + /** Ajoute un item dans un conteneur, sur la base + * de leurs ID */ + async ajouterDansConteneur(item, conteneur, onAjouterDansConteneur) { + if (!conteneur) { + // TODO: afficher + item.estContenu = false; + } + else if (conteneur.isConteneur()) { + item.estContenu = true; + await this.updateEmbeddedDocuments('Item', [{ + _id: conteneur.id, + 'system.contenu': [...conteneur.system.contenu, item.id] + }]); + onAjouterDansConteneur(item.id, conteneur.id); + } + } + + /* -------------------------------------------- */ + /** Fonction de remise à plat de l'équipement (ie vide les champs 'contenu') */ + async nettoyerConteneurs() { + RdDConfirm.confirmer({ + settingConfirmer: "confirmation-vider", + content: `

      Etes vous certain de vouloir vider tous les conteneurs ?

      `, + title: 'Vider les conteneurs', + buttonLabel: 'Vider', + onAction: async () => { + const corrections = []; + for (let item of this.items) { + if (item.estContenu) { + item.estContenu = undefined; + } + if (item.type == 'conteneur' && item.system.contenu.length > 0) { + corrections.push({ _id: item.id, 'system.contenu': [] }); + } + } + if (corrections.length > 0) { + await this.updateEmbeddedDocuments('Item', corrections); + } + } + }); + } + + /* -------------------------------------------- */ + buildSubConteneurObjetList(conteneurId, deleteList) { + let conteneur = this.getItem(conteneurId); + if (conteneur?.type == 'conteneur') { // Si c'est un conteneur + for (let subId of conteneur.system.contenu) { + let subObj = this.getItem(subId); + if (subObj) { + if (subObj.type == 'conteneur') { + this.buildSubConteneurObjetList(subId, deleteList); + } + deleteList.push({ id: subId, conteneurId: conteneurId }); + } + } + } + } + + /* -------------------------------------------- */ + async deleteAllConteneur(itemId, options) { + let list = []; + list.push({ id: itemId, conteneurId: undefined }); // Init list + this.buildSubConteneurObjetList(itemId, list); + await this.deleteEmbeddedDocuments('Item', list.map(it => it.id), options); + } + + /* -------------------------------------------- */ + /** Supprime un item d'un conteneur, sur la base + * de leurs ID */ + async enleverDeConteneur(item, conteneur, onEnleverDeConteneur) { + if (conteneur?.isConteneur()) { + item.estContenu = false; + await this.updateEmbeddedDocuments('Item', [{ + _id: conteneur.id, + 'system.contenu': conteneur.system.contenu.filter(id => id != item.id) + }]); + onEnleverDeConteneur(); + } + } + + /* -------------------------------------------- */ + async moveItemsBetweenActors(itemId, sourceActorId) { + let itemsList = [] + let sourceActor = game.actors.get(sourceActorId); + itemsList.push({ id: itemId, conteneurId: undefined }); // Init list + sourceActor.buildSubConteneurObjetList(itemId, itemsList); // Get itemId list + + const itemsDataToCreate = itemsList.map(it => sourceActor.getItem(it.id)) + .map(it => duplicate(it)) + .map(it => { it.system.contenu = []; return it; }); + let newItems = await this.createEmbeddedDocuments('Item', itemsDataToCreate); + + let itemMap = this._buildMapOldNewId(itemsList, newItems); + + for (let item of itemsList) { // Second boucle pour traiter la remise en conteneurs + // gestion conteneur/contenu + if (item.conteneurId) { // l'Objet était dans un conteneur + let newConteneurId = itemMap[item.conteneurId]; // Get conteneur + let newConteneur = this.getItem(newConteneurId); + + let newItemId = itemMap[item.id]; // Get newItem + + console.log('New conteneur filling!', newConteneur, newItemId, item); + let contenu = duplicate(newConteneur.system.contenu); + contenu.push(newItemId); + await this.updateEmbeddedDocuments('Item', [{ _id: newConteneurId, 'system.contenu': contenu }]); + } + } + for (let item of itemsList) { + await sourceActor.deleteEmbeddedDocuments('Item', [item.id]); + } + } + + _buildMapOldNewId(itemsList, newItems) { + let itemMap = {}; + for (let i = 0; i < itemsList.length; i++) { + itemMap[itemsList[i].id] = newItems[i].id; // Pour garder le lien ancien / nouveau + } + return itemMap; + } + /* -------------------------------------------- */ async postActorToChat(modeOverride) { let chatData = { diff --git a/module/rdd-main.js b/module/rdd-main.js index 7d68790f..13be7ddf 100644 --- a/module/rdd-main.js +++ b/module/rdd-main.js @@ -101,7 +101,7 @@ export class SystemReveDeDragon { /* -------------------------------------------- */ // Define custom Entity classes - CONFIG.Actor.documentClass = RdDActor; + CONFIG.Actor.documentClass = RdDBaseActor; CONFIG.Item.documentClass = RdDItem; CONFIG.RDD = { resolutionTable: RdDResolutionTable.resolutionTable, diff --git a/module/rdd-namegen.js b/module/rdd-namegen.js index f054f435..b27ea5bc 100644 --- a/module/rdd-namegen.js +++ b/module/rdd-namegen.js @@ -1,4 +1,4 @@ -import { RdDActor } from "./actor.js"; +import { RdDBaseActor } from "./actor/base-actor.js"; import { Misc } from "./misc.js"; import { RdDDice } from "./rdd-dice.js"; @@ -20,7 +20,7 @@ export class RdDNameGen { static async onCreerActeur(event) { const button = event.currentTarget; - await RdDActor.create({ + await RdDBaseActor.create({ name: button.attributes['data-nom'].value, type: button.attributes['data-type'].value }, diff --git a/templates/actor-sheet.html b/templates/actor-sheet.html index 3a824616..772f0e72 100644 --- a/templates/actor-sheet.html +++ b/templates/actor-sheet.html @@ -189,7 +189,7 @@

      Biographie :

      - {{editor biographie target="system.biographie" button=true owner=owner editable=true engine="prosemirror"}} + {{editor biographie target="system.biographie" button=true owner=options.owner editable=true engine="prosemirror"}}

      Notes :

      -- 2.35.3 From 5972db035dd3463f1a1a4b8a3b6e52d48d65cff2 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 1 Jan 2023 22:19:26 +0100 Subject: [PATCH 08/18] Permettre un arbre d'inventaire alternatif --- module/rdd-utility.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 98d210fe..083bcb95 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -296,7 +296,7 @@ export class RdDUtility { Handlebars.registerHelper('apostrophe', (article, str) => Grammar.apostrophe(article, str)); Handlebars.registerHelper('un', str => Grammar.articleIndetermine(str)); Handlebars.registerHelper('accord', (genre, ...args) => Grammar.accord(genre, args)); - Handlebars.registerHelper('buildConteneur', (objet) => { return new Handlebars.SafeString(RdDUtility.buildConteneur(objet)); }); + Handlebars.registerHelper('buildConteneur', (objet, tplItem) => { return new Handlebars.SafeString(RdDUtility.buildConteneur(objet, 1, tplItem)); }); Handlebars.registerHelper('buildContenu', (objet) => { return new Handlebars.SafeString(RdDUtility.buildContenu(objet, 1, true)); }); Handlebars.registerHelper('caseTmr-label', coord => TMRUtility.getTMRLabel(coord)); Handlebars.registerHelper('caseTmr-type', coord => TMRUtility.getTMRType(coord)); @@ -472,25 +472,29 @@ export class RdDUtility { /** Construit la structure récursive des conteneurs, avec imbrication potentielle * */ - static buildConteneur(objet, profondeur) { + static buildConteneur(objet, profondeur, tplItem) { if (!profondeur) profondeur = 1; + if (!tplItem) tplItem = 'actor/inventaire-item.html' objet.niveau = profondeur; + const isConteneur = objet.type == 'conteneur'; const isOuvert = isConteneur && this.getAfficheContenu(objet._id); const isVide = isConteneur && objet.system.contenu.length == 0; - const conteneur = Handlebars.partials['systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-item.html']({ + const conteneur = Handlebars.partials[`systems/foundryvtt-reve-de-dragon/templates/${tplItem}`]({ item: objet, vide: isVide, ouvert: isOuvert }); - const contenu = isConteneur ? RdDUtility.buildContenu(objet, profondeur, isOuvert) : ''; + const contenu = isConteneur ? RdDUtility.buildContenu(objet, profondeur, isOuvert, tplItem) : ''; return conteneur + contenu; } /* -------------------------------------------- */ - static buildContenu(objet, profondeur, afficherContenu) { + static buildContenu(objet, profondeur, afficherContenu, tplItem) { if (!profondeur) profondeur = 1; + if (!tplItem) tplItem = 'actor/inventaire-item.html' objet.niveau = profondeur; + const display = afficherContenu ? 'item-display-show' : 'item-display-hide'; let strContenu = `
        `; for (let subItem of objet.subItems) { -- 2.35.3 From ee42bdcf83d48653b3f4bd04dd3df6cba2522c07 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 1 Jan 2023 22:21:30 +0100 Subject: [PATCH 09/18] Ajout d'un Actor commerce --- icons/services/bacquet-eau.webp | Bin 0 -> 8298 bytes .../services.webp => services/commerce.webp} | Bin icons/services/compagnie.webp | Bin 0 -> 6582 bytes icons/services/lit.webp | Bin 0 -> 7202 bytes icons/services/paiement.webp | Bin 0 -> 5260 bytes lang/fr.json | 1 + module/actor/commerce-sheet.js | 68 +++++++++++++++++ module/actor/commerce.js | 48 ++++++++++++ module/item.js | 2 +- module/rdd-main.js | 4 + module/rdd-utility.js | 21 +++--- template.json | 6 +- templates/actor/commerce-actor-sheet.html | 71 ++++++++++++++++++ templates/actor/commerce-inventaire-item.html | 49 ++++++++++++ templates/actor/commerce-inventaire.html | 35 +++++++++ templates/actor/inventaire.html | 4 +- templates/item-service-sheet.html | 33 -------- 17 files changed, 296 insertions(+), 46 deletions(-) create mode 100644 icons/services/bacquet-eau.webp rename icons/{items/services.webp => services/commerce.webp} (100%) create mode 100644 icons/services/compagnie.webp create mode 100644 icons/services/lit.webp create mode 100644 icons/services/paiement.webp create mode 100644 module/actor/commerce-sheet.js create mode 100644 module/actor/commerce.js create mode 100644 templates/actor/commerce-actor-sheet.html create mode 100644 templates/actor/commerce-inventaire-item.html create mode 100644 templates/actor/commerce-inventaire.html diff --git a/icons/services/bacquet-eau.webp b/icons/services/bacquet-eau.webp new file mode 100644 index 0000000000000000000000000000000000000000..a8546ed391afd530d8afc413d5aebb24d0a70415 GIT binary patch literal 8298 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 literal 0 HcmV?d00001 diff --git a/icons/services/paiement.webp b/icons/services/paiement.webp new file mode 100644 index 0000000000000000000000000000000000000000..68d1f88787ac6d6640b731819f1bb62e63e35981 GIT binary patch literal 5260 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 zυ_(cr)xN0vC-*^5{5$Mp6jE?0}zNhN15o$H2>Wi7U`QE2K*8D$%4`_fO z;r6dZPUfPz^w@$lhQSi&{iUs}XX(Sd>=Zy^{RNj!ld$E9Su(0U_-Q}6z9jW466AHY zfT08Xm^gb~Yu)@9YiH}a?unf7j!M@)?oS?*3>So&5qY%n7*>~1mVf}1R> zzIzU`@ro%GYx1Ph$)LoZZ8jsa-zqnHcJxX^k8{&Zh`odCqGV@5PzT%SUTi5#v%r); zG^P{fNITzqpV|=edXngyy8!L6Gl!A9wU9nt-LsnEPqsfN+1R)WYbf{GWlpq0>q<0J zJ|P@9S0aaH2_(ZIRY4#efcv$Jq4XP&(#MtyY=##>mazhx9mP12PPXcCG8sf!Mz0yy z7!4vR>11Mp{6FN>!rV%KeWi5|}{SF}z@8tGABrg9g&TcbhChL3m|x!vdSZS@??M zPn~31(-uSangj+Qnq}FUDztP0tq_oT8LVX+pMx2ke{jCCqO0G$JbmFXt!lAH{V3SJ z{(hl0Yawxsp0=YYY1)8E<(dD&%*_v4={_ISuB%3NcP3~0QH#b$SvY%Geqx7#s_8Hm zKZS9#8D+`>geVm;1~H$_BpbWJ*pFEItX(aK)6oCT&h^XhE?QiRinJ`RLj}^1>@pV3 zUjJ)2sfF3?=y%3l_aohty4p^zmCU`)>W?dj2}`+L17|Ik=O}D0^H$o)^xpV`#V#vT K7tl{t2=FfeC1e}` literal 0 HcmV?d00001 diff --git a/lang/fr.json b/lang/fr.json index 36819273..8fa8f3fd 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -3,6 +3,7 @@ "TypePersonnage": "Personnage", "TypeCreature": "Créature", "TypeEntite": "Entité de cauchemar", + "TypeCommerce": "Commerce", "TypeVehicule": "Véhicule" }, "ITEM": { diff --git a/module/actor/commerce-sheet.js b/module/actor/commerce-sheet.js new file mode 100644 index 00000000..e1bbb08d --- /dev/null +++ b/module/actor/commerce-sheet.js @@ -0,0 +1,68 @@ +import { DialogItemAchat } from "../dialog-item-achat.js"; +import { RdDItem } from "../item.js"; +import { RdDSheetUtility } from "../rdd-sheet-utility.js"; +import { RdDUtility } from "../rdd-utility.js"; +import { RdDBaseActorSheet } from "./base-actor-sheet.js"; + +/** + * Extend the basic ActorSheet with some very simple modifications + * @extends {ActorSheet} + */ +export class RdDCommerceSheet extends RdDBaseActorSheet { + + /** @override */ + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + classes: ["rdd", "sheet", "actor"], + template: "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-actor-sheet.html", + width: 600, + height: 720, + tabs: [], + dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }] + }); + } + + /* -------------------------------------------- */ + /** @override */ + activateListeners(html) { + super.activateListeners(html); + + this.html.find('a.item-acheter').click(async event => await this.vente(this.getItem(event))); + + if (!this.options.editable) return; + + this.html.find('a.item-quantite-moins').click(async event => await this.getItem(event)?.quantiteIncDec(-1, { supprimerSiZero: false})); + this.html.find('a.item-quantite-plus').click(async event => await this.getItem(event)?.quantiteIncDec(1)); + this.html.find('input.item-quantite').change(async event => { + const newQuantite = Math.max(0, Number.parseInt(this.html.find(event.currentTarget).val())); + await this.getItem(event)?.update({ "system.quantite": newQuantite }); + }) + this.html.find('input.item-cout').change(async event => { + const newCout = Math.max(0, Number(this.html.find(event.currentTarget).val())); + await this.getItem(event)?.update({ "system.cout": newCout }); + }) + } + + async vente(item) { + const acheteur = RdDUtility.getSelectedActor(); + if (!acheteur) { + ui.notifications.warn(`Pas d'acheteur sélectionné`); + return; + } + const disponible = this.actor.getQuantiteDisponible(item) + if (disponible == 0) { + ui.notifications.warn(`${this.name} n'a plus de ${item.name} en vente`); + return; + } + + await DialogItemAchat.onAcheter({ + item, + vendeur: this.actor, + acheteur, + quantiteIllimite: disponible == undefined, + nbLots: disponible ?? 1, + tailleLot: 1, + prixLot: item.system.cout + }); + } +} diff --git a/module/actor/commerce.js b/module/actor/commerce.js new file mode 100644 index 00000000..bed83bee --- /dev/null +++ b/module/actor/commerce.js @@ -0,0 +1,48 @@ +import { RdDBaseActor } from "./base-actor.js"; + +export class RdDCommerce extends RdDBaseActor { + + static get defaultIcon() { + return "systems/foundryvtt-reve-de-dragon/icons/services/commerce.webp"; + } + + prepareData() { + super.prepareData(); + } + prepareDerivedData() { + super.prepareDerivedData(); + } + + canReceive(item) { + if (item.isInventaire()) { + return true; + } + return super.canReceive(item); + } + + getQuantiteDisponible(item) { + return this.system.illimite ? undefined : item.getQuantite(); + } + + verifierFortune(cout) { + return this.system.illimite || super.verifierFortune(cout); + } + async depenserSols(cout) { + if (this.system.illimite) { + return + } + await super.depenserSols(cout) + } + + async consommerNourritureAchetee(achat, vente, createdItemId) { + // ne pas consommer pour un commerce + } + + async decrementerQuantiteItem(itemVendu, quantite) { + if (this.system.illimite) { + return; + } + await super.decrementerQuantiteItem(itemVendu, quantite, {supprimerSiZero: false}); + } + +} \ No newline at end of file diff --git a/module/item.js b/module/item.js index 4deec4a1..f0b84c86 100644 --- a/module/item.js +++ b/module/item.js @@ -58,7 +58,7 @@ export const defaultItemImg = { poison: "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/venin.webp", oeuvre: "systems/foundryvtt-reve-de-dragon/icons/competence_comedie.webp", nourritureboisson: "systems/foundryvtt-reve-de-dragon/icons/objets/provision_crue.webp", - service: "systems/foundryvtt-reve-de-dragon/icons/items/services.webp", + service: "systems/foundryvtt-reve-de-dragon/icons/services/lit.webp", signedraconique: "systems/foundryvtt-reve-de-dragon/icons/tmr/signe_draconique.webp", gemme: "systems/foundryvtt-reve-de-dragon/icons/gemmes/almaze.webp", possession: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp", diff --git a/module/rdd-main.js b/module/rdd-main.js index 13be7ddf..2b13a1d2 100644 --- a/module/rdd-main.js +++ b/module/rdd-main.js @@ -37,6 +37,8 @@ import { RdDConteneurItemSheet } from "./item-conteneur-sheet.js"; import { RdDServiceItemSheet } from "./item-service-sheet.js"; import { RdDItemService } from "./item-service.js"; import { RdDBaseActor } from "./actor/base-actor.js"; +import { RdDCommerceSheet } from "./actor/commerce-sheet.js"; +import { RdDCommerce } from "./actor/commerce.js"; /** * RdD system @@ -62,6 +64,7 @@ export class SystemReveDeDragon { entite: RdDActor, personnage: RdDActor, vehicule: RdDActor, + commerce: RdDCommerce, } } @@ -113,6 +116,7 @@ export class SystemReveDeDragon { /* -------------------------------------------- */ // Register sheet application classes Actors.unregisterSheet("core", ActorSheet); + Actors.registerSheet(SYSTEM_RDD, RdDCommerceSheet, { types: ["commerce"], makeDefault: true }); Actors.registerSheet(SYSTEM_RDD, RdDActorSheet, { types: ["personnage"], makeDefault: true }); Actors.registerSheet(SYSTEM_RDD, RdDActorCreatureSheet, { types: ["creature"], makeDefault: true }); Actors.registerSheet(SYSTEM_RDD, RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true }); diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 083bcb95..f8bb2c42 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -170,6 +170,8 @@ export class RdDUtility { 'systems/foundryvtt-reve-de-dragon/templates/actor/liens-animaux.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/liens-suivants.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/liens-vehicules.html', + 'systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire.html', + 'systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire-item.html', //Items 'systems/foundryvtt-reve-de-dragon/templates/scripts/autocomplete-script.hbs', 'systems/foundryvtt-reve-de-dragon/templates/scripts/autocomplete.hbs', @@ -296,7 +298,7 @@ export class RdDUtility { Handlebars.registerHelper('apostrophe', (article, str) => Grammar.apostrophe(article, str)); Handlebars.registerHelper('un', str => Grammar.articleIndetermine(str)); Handlebars.registerHelper('accord', (genre, ...args) => Grammar.accord(genre, args)); - Handlebars.registerHelper('buildConteneur', (objet, tplItem) => { return new Handlebars.SafeString(RdDUtility.buildConteneur(objet, 1, tplItem)); }); + Handlebars.registerHelper('buildConteneur', (objet, templateItem, options) => { return new Handlebars.SafeString(RdDUtility.buildConteneur(objet, 1, templateItem, options)); }); Handlebars.registerHelper('buildContenu', (objet) => { return new Handlebars.SafeString(RdDUtility.buildContenu(objet, 1, true)); }); Handlebars.registerHelper('caseTmr-label', coord => TMRUtility.getTMRLabel(coord)); Handlebars.registerHelper('caseTmr-type', coord => TMRUtility.getTMRType(coord)); @@ -472,33 +474,34 @@ export class RdDUtility { /** Construit la structure récursive des conteneurs, avec imbrication potentielle * */ - static buildConteneur(objet, profondeur, tplItem) { + static buildConteneur(objet, profondeur, templateItem, options) { if (!profondeur) profondeur = 1; - if (!tplItem) tplItem = 'actor/inventaire-item.html' + if (!templateItem) templateItem = 'actor/inventaire-item.html' objet.niveau = profondeur; const isConteneur = objet.type == 'conteneur'; const isOuvert = isConteneur && this.getAfficheContenu(objet._id); const isVide = isConteneur && objet.system.contenu.length == 0; - const conteneur = Handlebars.partials[`systems/foundryvtt-reve-de-dragon/templates/${tplItem}`]({ + const conteneur = Handlebars.partials[`systems/foundryvtt-reve-de-dragon/templates/${templateItem}`]({ item: objet, vide: isVide, - ouvert: isOuvert + ouvert: isOuvert, + options: options }); - const contenu = isConteneur ? RdDUtility.buildContenu(objet, profondeur, isOuvert, tplItem) : ''; + const contenu = isConteneur ? RdDUtility.buildContenu(objet, profondeur, isOuvert, templateItem, options) : ''; return conteneur + contenu; } /* -------------------------------------------- */ - static buildContenu(objet, profondeur, afficherContenu, tplItem) { + static buildContenu(objet, profondeur, afficherContenu, templateItem, options) { if (!profondeur) profondeur = 1; - if (!tplItem) tplItem = 'actor/inventaire-item.html' + if (!templateItem) templateItem = 'actor/inventaire-item.html' objet.niveau = profondeur; const display = afficherContenu ? 'item-display-show' : 'item-display-hide'; let strContenu = `
          `; for (let subItem of objet.subItems) { - strContenu += this.buildConteneur(subItem, profondeur + 1); + strContenu += this.buildConteneur(subItem, profondeur + 1, templateItem, options); } return strContenu + "
        "; } diff --git a/template.json b/template.json index 63f2374d..15f2ff4e 100644 --- a/template.json +++ b/template.json @@ -1,6 +1,6 @@ { "Actor": { - "types": ["personnage", "creature", "entite", "vehicule"], + "types": ["personnage", "creature", "entite", "commerce", "vehicule"], "templates": { "description": { "description": "Description ...", @@ -554,6 +554,10 @@ }, "vehicule": { "templates": [ "vehicule", "description" ] + }, + "commerce":{ + "templates": [ "description" ], + "illimite": false } }, "Item": { diff --git a/templates/actor/commerce-actor-sheet.html b/templates/actor/commerce-actor-sheet.html new file mode 100644 index 00000000..1f80cfbd --- /dev/null +++ b/templates/actor/commerce-actor-sheet.html @@ -0,0 +1,71 @@ + + + {{!-- Sheet Header --}} +
        +
        +
        + +
        +

        + {{#if @root.options.isObserver}} +
        + + Quantité illimitée en vente +
        + {{/if}} +
        +
        +
        +
        + + {{!-- Sheet Body --}} +
        +
        + {{editor description target="system.description" button=true owner=options.owner editable=options.isOwner engine="prosemirror"}} +
        +
        + {{> "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire.html"}} + {{#unless system.illimite}} + {{#if @root.options.isObserver}} +
        + {{> "systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-monnaie.html"}} + {{/if}} + {{/unless}} + {{!-- +
        +
        +
          +
        • + + + + + +
        • + {{#each system.services as |service key|}} +
        • + + + + +
          + + {{#unless @root.disabled}} + + + {{/unless}} +
          +
        • + {{/each}} +
        +
        + --}} +
        + {{> "systems/foundryvtt-reve-de-dragon/templates/actor/editor-notes-mj.html"}} +
        +
        + \ No newline at end of file diff --git a/templates/actor/commerce-inventaire-item.html b/templates/actor/commerce-inventaire-item.html new file mode 100644 index 00000000..81b25fee --- /dev/null +++ b/templates/actor/commerce-inventaire-item.html @@ -0,0 +1,49 @@ +{{#if (ne item.type 'monnaie')}} +
      • + + + {{#if (eq item.type 'conteneur')}} + + {{/if}} + + {{item.name}} + + + {{#unless @root.system.illimite}} + + {{#unless (and (eq item.type 'conteneur') (not vide))}} + {{#if @root.options.isOwner}} + + {{/if}} + + {{#if @root.options.isOwner}} + + {{/if}} + {{/unless}} + + {{/unless}} + + {{#unless (and (eq item.type 'conteneur') (not vide))}} + + {{/unless}} + + + {{#unless (and (eq item.type 'conteneur') (not vide))}} + {{#if @root.options.isOwner}} + + + {{#if (or @root.system.illimite (ne item.system.quantite 0))}} + + {{/if}} + {{/if}} + + {{#if (gt item.system.quantite 0)}} + + {{/if}} + {{/unless}} + +
      • +{{/if}} diff --git a/templates/actor/commerce-inventaire.html b/templates/actor/commerce-inventaire.html new file mode 100644 index 00000000..0cff801e --- /dev/null +++ b/templates/actor/commerce-inventaire.html @@ -0,0 +1,35 @@ +

        Boutique

        + + {{#if options.isGM}} + Nouvel objet + Tout vider + {{/if}} + + {{#unless @root.system.illimite}} + {{#if calc.surEncombrementMessage}}{{calc.surEncombrementMessage}} ‐{{/if}} + Encombrement: {{numberFormat calc.encTotal decimals=2}} + {{#if (regle-optionnelle 'afficher-prix-joueurs')}} + ‐ Valeur: {{numberFormat calc.prixTotalEquipement decimals=2}} Sols + {{/if}} + {{/unless}} + +
          +
        • + Nom + {{#unless @root.system.illimite}} + Quantité + {{/unless}} + Prix (sols) + Actions +
        • + {{#each objets as |item id|}} + {{#unless item.estContenu}} + {{#if (ne item.type 'conteneur')}} + {{> "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire-item.html" item=item vide=true ouvert=true options=@root.options}} + {{/if}} + {{/unless}} + {{/each}} + {{#each conteneurs as |conteneur id|}} + {{buildConteneur this 'actor/commerce-inventaire-item.html' @root.options}} + {{/each}} +
        diff --git a/templates/actor/inventaire.html b/templates/actor/inventaire.html index 1456e8fe..c080c069 100644 --- a/templates/actor/inventaire.html +++ b/templates/actor/inventaire.html @@ -20,11 +20,11 @@ {{#each objets as |item id|}} {{#unless item.estContenu}} {{#if (ne item.type 'conteneur')}} - {{> "systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-item.html" item=item vide=true ouvert=true }} + {{> "systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-item.html" item=item vide=true ouvert=true options=@root.options}} {{/if}} {{/unless}} {{/each}} {{#each conteneurs as |conteneur id|}} - {{buildConteneur this}} + {{buildConteneur this 'actor/inventaire-item.html' @root.options}} {{/each}}
      diff --git a/templates/item-service-sheet.html b/templates/item-service-sheet.html index 534fdd76..8e8f0ee0 100644 --- a/templates/item-service-sheet.html +++ b/templates/item-service-sheet.html @@ -5,39 +5,6 @@
      {{editor description target="system.description" button=true owner=owner editable=(or isGM isOwner) engine="prosemirror"}}
      - {{!-- -
      -
        -
      • - - - - - -
      • - {{#each system.services as |service key|}} -
      • - - - - -
        - - {{#unless @root.disabled}} - - - {{/unless}} -
        -
      • - {{/each}} -
      -
      -
      - --}}
      Quantité en vente illimitée -- 2.35.3 From 128d7adf89a4a4ce3dfa7d4f7729ea2588c48602 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Mon, 2 Jan 2023 22:49:45 +0100 Subject: [PATCH 10/18] Migration des services en commerces --- module/migrations.js | 66 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/module/migrations.js b/module/migrations.js index f2765567..9a553f80 100644 --- a/module/migrations.js +++ b/module/migrations.js @@ -1,6 +1,9 @@ +import { RdDBaseActor } from "./actor/base-actor.js"; import { LOG_HEAD, SYSTEM_RDD } from "./constants.js"; import { Environnement } from "./environnement.js"; import { Grammar } from "./grammar.js"; +import { Monnaie } from "./item-monnaie.js"; +import { RdDItem } from "./item.js"; class Migration { get code() { return "sample"; } @@ -41,9 +44,9 @@ class _1_5_34_migrationPngWebp { } function prepareDocumentsImgUpdate(documents) { return documents.filter(it => it.img && it.img.match(regexOldPngJpg)) - .map(it => { - return { _id: it.id, img: convertImgToWebp(it.img) } - }); + .map(it => { + return { _id: it.id, img: convertImgToWebp(it.img) } + }); } const itemsUpdates = prepareDocumentsImgUpdate(game.items); @@ -325,6 +328,46 @@ class _10_3_17_Monnaies extends Migration { } } +class _10_4_6_ServicesEnCommerces extends Migration { + + get code() { return "migration-service-acteurs"; } + get version() { return "10.4.6"; } + + async migrate() { + const servicesToMigrate = game.items.filter(it => it.type == 'service'); + servicesToMigrate.forEach(async service => { + const commerce = await this.convertServiceToCommerce(service); + await RdDBaseActor.create(commerce, { renderSheet: false }); + await service.delete(); + }); + } + + async convertServiceToCommerce(service) { + return { + name: service.name, img: service.img, type: 'commerce', + system: { + description: service.system.description, + notesmj: service.system.descriptionmj, + illimite: service.system.illimite + }, + items: await this.transformInventaireCommerce(service) + } + } + async transformInventaireCommerce(service) { + const serviceItems = (service.system.items ?? []); + const commerceItems = await Promise.all(serviceItems.map(async (it) => { return await this.transformToItemBoutique(it); })); + return commerceItems.concat(Monnaie.monnaiesStandard()); + } + + async transformToItemBoutique(serviceRefItem) { + const item = await RdDItem.getCorrespondingItem(serviceRefItem); + const itemToCreate = { + name: item.name, img: item.img, type: item.type, + system: mergeObject({ cout: serviceRefItem.system.cout, quantite: serviceRefItem.system.quantite }, item.system, { overwrite: false }) + }; + return itemToCreate; + } +} export class Migrations { static getMigrations() { @@ -338,7 +381,8 @@ export class Migrations { new _10_2_10_DesirLancinant_IdeeFixe(), new _10_3_0_Inventaire(), new _10_3_0_FrequenceEnvironnement(), - new _10_3_17_Monnaies() + new _10_3_17_Monnaies(), + new _10_4_6_ServicesEnCommerces(), ]; } @@ -355,16 +399,10 @@ export class Migrations { migrate() { 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 */ + //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) => - isNewerVersion(a.version, b.version) - ? 1 - : isNewerVersion(b.version, a.version) - ? -1 - : 0 - ); + migrations.sort((a, b) => this.compareVersions(a, b)); migrations.forEach(async (m) => { ui.notifications.info( `Executing migration ${m.code}: version ${currentVersion} is lower than ${m.version}` @@ -390,4 +428,8 @@ export class Migrations { console.log(LOG_HEAD + `No system version changed`); } } + + compareVersions(a, b) { + return isNewerVersion(a.version, b.version) ? 1 : isNewerVersion(b.version, a.version) ? -1 : 0; + } } -- 2.35.3 From 87f12019ac6d0c1585870f26c9fb8872260e42e1 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Tue, 3 Jan 2023 00:30:00 +0100 Subject: [PATCH 11/18] Cleanup partials --- module/rdd-utility.js | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/module/rdd-utility.js b/module/rdd-utility.js index f8bb2c42..0e739fb7 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -180,32 +180,6 @@ export class RdDUtility { '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', - 'systems/foundryvtt-reve-de-dragon/templates/item-arme-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-armure-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-objet-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-conteneur-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-sort-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-herbe-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-ingredient-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-faune-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-livre-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-tache-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-potion-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-rencontre-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-queue-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-souffle-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-tarot-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-tete-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-ombre-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-monnaie-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-meditation-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-nourritureboisson-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-possession-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-extraitpoetique-sheet.html', - 'systems/foundryvtt-reve-de-dragon/templates/item-service-sheet.html', // partial enums 'systems/foundryvtt-reve-de-dragon/templates/enum-caracteristiques.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-base-competence.html', -- 2.35.3 From d4ddc4e940281df65ab15a93f01551ae419c7e23 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Tue, 3 Jan 2023 00:31:32 +0100 Subject: [PATCH 12/18] Services pour Commerces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les services sont modifiés pour correspondre aux nouveaux commerces --- lang/fr.json | 2 +- module/actor/base-actor-sheet.js | 28 ++-- module/actor/base-actor.js | 30 ++-- module/actor/commerce-sheet.js | 5 + module/actor/commerce.js | 2 +- module/item-service-sheet.js | 65 --------- module/item-service.js | 138 +----------------- module/item.js | 22 +-- template.json | 8 +- templates/actor/commerce-inventaire-item.html | 16 +- templates/item-service-sheet.html | 74 ++-------- 11 files changed, 77 insertions(+), 313 deletions(-) diff --git a/lang/fr.json b/lang/fr.json index 8fa8f3fd..f857f204 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -28,7 +28,7 @@ "TypeArmure": "Armure", "TypeConteneur": "Conteneur", "TypeNourritureboisson": "Nourriture & boisson", - "TypeService": "Services/Boutique", + "TypeService": "Service", "TypeChant": "Chant", "TypeDanse": "Danse", "TypeMusique": "Musique", diff --git a/module/actor/base-actor-sheet.js b/module/actor/base-actor-sheet.js index 328e2b72..6cfc9e7e 100644 --- a/module/actor/base-actor-sheet.js +++ b/module/actor/base-actor-sheet.js @@ -77,7 +77,6 @@ export class RdDBaseActorSheet extends ActorSheet { /* -------------------------------------------- */ filterItemsPerTypeForSheet(formData, itemTypes) { - formData.services = Misc.arrayOrEmpty(itemTypes['service']); formData.recettescuisine = Misc.arrayOrEmpty(itemTypes['recettecuisine']); formData.recettesAlchimiques = Misc.arrayOrEmpty(itemTypes['recettealchimique']); formData.maladies = Misc.arrayOrEmpty(itemTypes['maladie']); @@ -103,9 +102,8 @@ export class RdDBaseActorSheet extends ActorSheet { formData.oeuvres = Misc.arrayOrEmpty(itemTypes['oeuvre']); formData.jeux = Misc.arrayOrEmpty(itemTypes['jeu']); - + formData.services = Misc.arrayOrEmpty(itemTypes['service']); formData.conteneurs = Misc.arrayOrEmpty(itemTypes['conteneur']); - formData.materiel = Misc.arrayOrEmpty(itemTypes['objet']); formData.armes = Misc.arrayOrEmpty(itemTypes['arme']); formData.armures = Misc.arrayOrEmpty(itemTypes['armure']); @@ -117,22 +115,12 @@ export class RdDBaseActorSheet extends ActorSheet { formData.herbes = Misc.arrayOrEmpty(itemTypes['herbe']); formData.nourritureboissons = Misc.arrayOrEmpty(itemTypes['nourritureboisson']); formData.gemmes = Misc.arrayOrEmpty(itemTypes['gemme']); - formData.monnaie = Misc.arrayOrEmpty(itemTypes['monnaie']).sort(Monnaie.triValeurEntiere()); - formData.objets = formData.conteneurs - .concat(formData.materiel) - .concat(formData.armes) - .concat(formData.armures) - .concat(formData.munitions) - .concat(formData.livres) - .concat(formData.potions) - .concat(formData.ingredients) - .concat(formData.herbes) - .concat(formData.faunes) - .concat(formData.monnaie) - .concat(formData.nourritureboissons) - .concat(formData.gemmes); + formData.objets = RdDItem.getItemTypesInventaire('all') + .map(t => Misc.arrayOrEmpty(itemTypes[t])) + .reduce((a, b) => a.concat(b), []) + .sort(Misc.ascending(it => it.name)); } /* -------------------------------------------- */ /** @override */ @@ -205,7 +193,7 @@ export class RdDBaseActorSheet extends ActorSheet { /* -------------------------------------------- */ async selectObjetTypeToCreate() { - let typeObjets = RdDItem.getItemTypesInventaire(); + let typeObjets = this.getTypesInventaire().sort(Misc.ascending(type => Misc.typeName('Item', type))); let content = `Selectionnez le type d'équipement - {{#if @root.options.isOwner}} - - {{/if}} + {{#unless (or (eq item.type 'service') (and (eq item.type 'conteneur') (not vide)))}} + {{#if @root.options.isOwner}} + + {{/if}} + + {{#if @root.options.isOwner}} + + {{/if}} {{/unless}} {{/unless}} diff --git a/templates/item-service-sheet.html b/templates/item-service-sheet.html index 8e8f0ee0..bcb7de4f 100644 --- a/templates/item-service-sheet.html +++ b/templates/item-service-sheet.html @@ -2,69 +2,23 @@ {{>"systems/foundryvtt-reve-de-dragon/templates/header-item.html"}}
      -
      - {{editor description target="system.description" button=true owner=owner editable=(or isGM isOwner) engine="prosemirror"}} -
      - - Quantité en vente illimitée + Jet de moral en situation heureuse +
      -
      -
        -
      • - - {{#unless system.illimite}} - - {{/unless}} - -
        - {{#unless disabled}} - - - - {{/unless}} -
        -
      • - {{#each system.items as |item key|}} -
      • - - {{#unless @root.system.illimite}} - - {{#unless @root.disabled}} - - {{/unless}} - - {{#unless @root.disabled}} - - {{/unless}} - - {{/unless}} - - - -
        - - {{#unless @root.disabled}} - - - {{/unless}} -
        -
      • - {{/each}} -
      + +
      + +
      - {{#if isGM}} -
      -
      - -
      - {{editor descriptionmj target="system.descriptionmj" button=true owner=owner editable=true engine="prosemirror"}} -
      + +
      + +
      - {{/if}} + + {{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.html"}}
      -- 2.35.3 From aa5d175027d53f0990c888a93ff3907fc4b49d20 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Tue, 3 Jan 2023 01:03:05 +0100 Subject: [PATCH 13/18] Formatage de prix --- templates/chat-vente-item.html | 2 +- templates/dialog-item-achat.html | 4 ++-- templates/dialog-item-vente.html | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/templates/chat-vente-item.html b/templates/chat-vente-item.html index 4bfb7e23..ad5afd1d 100644 --- a/templates/chat-vente-item.html +++ b/templates/chat-vente-item.html @@ -19,7 +19,7 @@ {{/if}} {{#if (ne prixLot 0)}} Prix {{#if (gt tailleLot 1)}}du lot {{else}}unitaire{{/if}}: - {{prixLot}} Sols
      + {{numberFormat prixLot decimals=2 sign=false}} Sols
      {{/if}}

      {{#if (or (gt quantiteNbLots 0) quantiteIllimite)}} diff --git a/templates/dialog-item-achat.html b/templates/dialog-item-achat.html index 03b83a2d..f6ecffb2 100644 --- a/templates/dialog-item-achat.html +++ b/templates/dialog-item-achat.html @@ -83,12 +83,12 @@ {{#if isVente}}
      - +
      - {{prixTotal}} + {{numberFormat prixTotal decimals=2 sign=false}} Sols
      diff --git a/templates/dialog-item-vente.html b/templates/dialog-item-vente.html index 4a0f1051..52d78e42 100644 --- a/templates/dialog-item-vente.html +++ b/templates/dialog-item-vente.html @@ -26,13 +26,13 @@ max="{{quantiteMax}}" value="{{tailleLot}}" data-dtype="Number" />
      - - + +
      - -- 2.35.3 From 7ca3306c6f8122d4e6687ab1fea68acd04fb95ac Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Tue, 3 Jan 2023 01:19:38 +0100 Subject: [PATCH 14/18] Fix: cacher quantite illimite dans les contenants --- templates/actor/commerce-inventaire-item.html | 5 +++-- templates/actor/commerce-inventaire.html | 9 +++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/templates/actor/commerce-inventaire-item.html b/templates/actor/commerce-inventaire-item.html index 09a281c4..ce23067e 100644 --- a/templates/actor/commerce-inventaire-item.html +++ b/templates/actor/commerce-inventaire-item.html @@ -12,7 +12,8 @@ {{item.name}} - {{#unless @root.system.illimite}} + {{log 'item-inventaire' this}} + {{#unless item.parent.system.illimite}} {{#unless (or (eq item.type 'service') (and (eq item.type 'conteneur') (not vide)))}} {{#if @root.options.isOwner}} @@ -35,7 +36,7 @@ {{#if @root.options.isOwner}} - {{#if (or @root.system.illimite (ne item.system.quantite 0))}} + {{#if (or item.parent.system.illimite (ne item.system.quantite 0))}} {{/if}} {{/if}} diff --git a/templates/actor/commerce-inventaire.html b/templates/actor/commerce-inventaire.html index 0cff801e..934560f8 100644 --- a/templates/actor/commerce-inventaire.html +++ b/templates/actor/commerce-inventaire.html @@ -5,7 +5,7 @@ Tout vider {{/if}} - {{#unless @root.system.illimite}} + {{#unless system.illimite}} {{#if calc.surEncombrementMessage}}{{calc.surEncombrementMessage}} ‐{{/if}} Encombrement: {{numberFormat calc.encTotal decimals=2}} {{#if (regle-optionnelle 'afficher-prix-joueurs')}} @@ -16,7 +16,7 @@
      • Nom - {{#unless @root.system.illimite}} + {{#unless system.illimite}} Quantité {{/unless}} Prix (sols) @@ -25,11 +25,12 @@ {{#each objets as |item id|}} {{#unless item.estContenu}} {{#if (ne item.type 'conteneur')}} - {{> "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire-item.html" item=item vide=true ouvert=true options=@root.options}} + {{> "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire-item.html" + item=item vide=true ouvert=true options=../options}} {{/if}} {{/unless}} {{/each}} {{#each conteneurs as |conteneur id|}} - {{buildConteneur this 'actor/commerce-inventaire-item.html' @root.options}} + {{buildConteneur conteneur 'actor/commerce-inventaire-item.html' ../options}} {{/each}}
      -- 2.35.3 From d5453c9b046f68678a2bb035ef744286bf3d973a Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Tue, 3 Jan 2023 01:37:07 +0100 Subject: [PATCH 15/18] Ajout d'images de services --- icons/services/biere.webp | Bin 0 -> 6350 bytes icons/services/brandevin.webp | Bin 0 -> 6128 bytes icons/services/repas.webp | Bin 0 -> 6062 bytes icons/services/verre.webp | Bin 0 -> 5250 bytes icons/services/vin.webp | Bin 0 -> 5680 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 icons/services/biere.webp create mode 100644 icons/services/brandevin.webp create mode 100644 icons/services/repas.webp create mode 100644 icons/services/verre.webp create mode 100644 icons/services/vin.webp diff --git a/icons/services/biere.webp b/icons/services/biere.webp new file mode 100644 index 0000000000000000000000000000000000000000..cd1d443c31c638cccf8366c5dccf4010b2441401 GIT binary patch literal 6350 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 literal 0 HcmV?d00001 diff --git a/icons/services/repas.webp b/icons/services/repas.webp new file mode 100644 index 0000000000000000000000000000000000000000..d51e25a35ac144862504e1c0162595eabc11a4eb GIT binary patch literal 6062 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 literal 0 HcmV?d00001 diff --git a/icons/services/verre.webp b/icons/services/verre.webp new file mode 100644 index 0000000000000000000000000000000000000000..f05bf758b70b7187dfa77ea04777b84c00478654 GIT binary patch literal 5250 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 literal 0 HcmV?d00001 diff --git a/icons/services/vin.webp b/icons/services/vin.webp new file mode 100644 index 0000000000000000000000000000000000000000..1e2d1ce8bc8769a2d4cfe8b1bc0a903cf0bfdd32 GIT binary patch literal 5680 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 KvD< Date: Tue, 3 Jan 2023 01:37:50 +0100 Subject: [PATCH 16/18] Les commerces peuvent appliquer un pourcentage --- module/actor/commerce-sheet.js | 3 ++- module/actor/commerce.js | 5 +++++ module/dialog-item-vente.js | 6 +++--- module/item-service.js | 2 +- module/item.js | 9 ++++++++- module/rdd-utility.js | 2 ++ template.json | 1 + templates/actor/commerce-actor-sheet.html | 10 +++++++++- templates/actor/commerce-inventaire-item.html | 20 +++++++++++++------ 9 files changed, 45 insertions(+), 13 deletions(-) diff --git a/module/actor/commerce-sheet.js b/module/actor/commerce-sheet.js index 6df94ed5..0aa89a2a 100644 --- a/module/actor/commerce-sheet.js +++ b/module/actor/commerce-sheet.js @@ -3,6 +3,7 @@ import { RdDItem } from "../item.js"; import { RdDSheetUtility } from "../rdd-sheet-utility.js"; import { RdDUtility } from "../rdd-utility.js"; import { RdDBaseActorSheet } from "./base-actor-sheet.js"; +import { RdDCommerce } from "./commerce.js"; /** * Extend the basic ActorSheet with some very simple modifications @@ -67,7 +68,7 @@ export class RdDCommerceSheet extends RdDBaseActorSheet { quantiteIllimite: disponible == undefined, nbLots: disponible ?? 1, tailleLot: 1, - prixLot: item.system.cout + prixLot: item.calculerPrixCommercant() }); } } diff --git a/module/actor/commerce.js b/module/actor/commerce.js index c29b318d..2735ac5e 100644 --- a/module/actor/commerce.js +++ b/module/actor/commerce.js @@ -1,3 +1,4 @@ +import { Misc } from "../misc.js"; import { RdDBaseActor } from "./base-actor.js"; export class RdDCommerce extends RdDBaseActor { @@ -45,4 +46,8 @@ export class RdDCommerce extends RdDBaseActor { await super.decrementerQuantiteItem(itemVendu, quantite, {supprimerSiZero: false}); } + calculerPrix(item) { + const pourcentage = this.system.pourcentage ?? 100; + return Misc.keepDecimals(Math.ceil(item.system.cout * pourcentage)/100, 2); + } } \ No newline at end of file diff --git a/module/dialog-item-vente.js b/module/dialog-item-vente.js index a027ef61..78698d2a 100644 --- a/module/dialog-item-vente.js +++ b/module/dialog-item-vente.js @@ -9,9 +9,9 @@ export class DialogItemVente extends Dialog { item: item, alias: item.actor?.name ?? game.user.name, vendeurId: item.actor?.id , - prixOrigine: item.system.cout, - prixUnitaire: item.system.cout, - prixLot: item.system.cout, + prixOrigine: item.calculerPrixCommercant(), + prixUnitaire: item.calculerPrixCommercant(), + prixLot: item.calculerPrixCommercant(), tailleLot: 1, quantiteNbLots: quantite, quantiteMaxLots: quantite, diff --git a/module/item-service.js b/module/item-service.js index 6d116dfa..95e192b7 100644 --- a/module/item-service.js +++ b/module/item-service.js @@ -11,7 +11,7 @@ export class RdDItemService extends RdDItem { return [ RdDItem.propertyIfDefined('Qualité', this.system.qualite, this.system.qualite != 0), RdDItem.propertyIfDefined('Moral', 'Situation heureuse', this.system.moral), - RdDItem.propertyIfDefined('Coût', `${this.system.cout} sols`), + RdDItem.propertyIfDefined('Coût', `${this.calculerPrixCommercant()} sols`), ]; } } \ No newline at end of file diff --git a/module/item.js b/module/item.js index ac7ed712..5e9944bc 100644 --- a/module/item.js +++ b/module/item.js @@ -171,7 +171,6 @@ export class RdDItem extends Item { return typesObjetsConnaissance.includes(this.type) } - getItemGroup() { if (this.isInventaire()) return "equipement"; if (this.isOeuvre()) return "oeuvre"; @@ -258,6 +257,14 @@ export class RdDItem extends Item { return this.system.cout ?? 0 } + calculerPrixCommercant() { + if (this.parent?.type == 'commerce') { + // appliquer le pourcentage + return this.parent.calculerPrix(this); + } + return this.system.cout; + } + prepareDerivedData() { super.prepareDerivedData(); if (this.isInventaire()) { diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 0e739fb7..be4091d0 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -16,6 +16,7 @@ import { RdDCalendrier } from "./rdd-calendrier.js"; import { Environnement } from "./environnement.js"; import { RdDItemCompetence } from "./item-competence.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js"; +import { RdDCommerce } from "./actor/commerce.js"; /* -------------------------------------------- */ // This table starts at 0 -> niveau -10 @@ -274,6 +275,7 @@ export class RdDUtility { Handlebars.registerHelper('accord', (genre, ...args) => Grammar.accord(genre, args)); Handlebars.registerHelper('buildConteneur', (objet, templateItem, options) => { return new Handlebars.SafeString(RdDUtility.buildConteneur(objet, 1, templateItem, options)); }); Handlebars.registerHelper('buildContenu', (objet) => { return new Handlebars.SafeString(RdDUtility.buildContenu(objet, 1, true)); }); + Handlebars.registerHelper('calculerPrixCommercant', item => item.calculerPrixCommercant()); Handlebars.registerHelper('caseTmr-label', coord => TMRUtility.getTMRLabel(coord)); Handlebars.registerHelper('caseTmr-type', coord => TMRUtility.getTMRType(coord)); Handlebars.registerHelper('typeTmr-name', type => TMRUtility.typeTmrName(type)); diff --git a/template.json b/template.json index ed26bd06..7abda35a 100644 --- a/template.json +++ b/template.json @@ -557,6 +557,7 @@ }, "commerce":{ "templates": [ "description" ], + "pourcentage": 100, "illimite": false } }, diff --git a/templates/actor/commerce-actor-sheet.html b/templates/actor/commerce-actor-sheet.html index 1f80cfbd..4792bbe7 100644 --- a/templates/actor/commerce-actor-sheet.html +++ b/templates/actor/commerce-actor-sheet.html @@ -10,7 +10,15 @@ {{#if @root.options.isObserver}}
      - Quantité illimitée en vente + +
      +
      + + + +
      {{/if}}
      diff --git a/templates/actor/commerce-inventaire-item.html b/templates/actor/commerce-inventaire-item.html index ce23067e..c25239ac 100644 --- a/templates/actor/commerce-inventaire-item.html +++ b/templates/actor/commerce-inventaire-item.html @@ -1,7 +1,7 @@ {{#if (ne item.type 'monnaie')}}
    • - + {{#if (eq item.type 'conteneur')}} {{#unless (or (eq item.type 'service') (and (eq item.type 'conteneur') (not vide)))}} - {{#if @root.options.isOwner}} + {{#if options.isOwner}} {{/if}} - - {{#if @root.options.isOwner}} + + {{#if options.isOwner}} {{/if}} {{/unless}} @@ -28,12 +30,18 @@ {{/unless}} {{#unless (and (eq item.type 'conteneur') (not vide))}} - + {{/unless}} {{#unless (and (eq item.type 'conteneur') (not vide))}} - {{#if @root.options.isOwner}} + {{#if options.isOwner}} {{#if (or item.parent.system.illimite (ne item.system.quantite 0))}} -- 2.35.3 From 80be0490ebf829c1aacad8b8d76191c612364b6f Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Tue, 3 Jan 2023 02:20:16 +0100 Subject: [PATCH 17/18] =?UTF-8?q?Permettre=20d'=C3=A9diter=20les=20contene?= =?UTF-8?q?urs=20de=20regroupement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- templates/actor/commerce-inventaire-item.html | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/templates/actor/commerce-inventaire-item.html b/templates/actor/commerce-inventaire-item.html index c25239ac..313b4ef4 100644 --- a/templates/actor/commerce-inventaire-item.html +++ b/templates/actor/commerce-inventaire-item.html @@ -40,19 +40,25 @@ {{/unless}} - {{#unless (and (eq item.type 'conteneur') (not vide))}} {{#if options.isOwner}} - - - {{#if (or item.parent.system.illimite (ne item.system.quantite 0))}} - - {{/if}} + {{#if (and (eq item.type 'conteneur') (not vide))}} + + {{else}} + + + {{#if (or item.parent.system.illimite (ne item.system.quantite 0))}} + + {{/if}} + {{#if (gt item.system.quantite 0)}} + + {{/if}} + {{/if}} + {{else}} + {{#if (or item.parent.system.illimite (gt item.system.quantite 0))}} + + {{/if}} {{/if}} - {{#if (gt item.system.quantite 0)}} - - {{/if}} - {{/unless}}
    • {{/if}} -- 2.35.3 From 060943ee5389271ac9588e30f774391ad9ca274e Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Tue, 3 Jan 2023 02:20:28 +0100 Subject: [PATCH 18/18] Version 10.4.6 --- system.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system.json b/system.json index f97cffcf..d51dea1d 100644 --- a/system.json +++ b/system.json @@ -1,8 +1,8 @@ { "id": "foundryvtt-reve-de-dragon", "title": "Rêve de Dragon", - "version": "10.4.5", - "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-10.4.5.zip", + "version": "10.4.6", + "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-10.4.6.zip", "manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v10/system.json", "compatibility": { "minimum": "10", -- 2.35.3