diff --git a/module/actor.js b/module/actor.js index d4106077..4b63b1d5 100644 --- a/module/actor.js +++ b/module/actor.js @@ -3642,20 +3642,13 @@ export class RdDActor extends Actor { return; } - /* -------------------------------------------- */ - getFortune() { - return this.itemTypes['monnaie'] - .map(m => Number(m.system.cout) * Number(m.system.quantite)) - .reduce(Misc.sum(), 0); - } - /* -------------------------------------------- */ async payerSols(depense) { depense = Number(depense); if (depense == 0) { return; } - let fortune = this.getFortune(); + let fortune = Monnaie.getFortune(this); console.log("payer", game.user.character, depense, fortune); let msg = ""; if (fortune >= depense) { @@ -3674,7 +3667,7 @@ export class RdDActor extends Actor { } async depenserSols(sols) { - let reste = this.getFortune() - Number(sols); + let reste = Monnaie.getFortune(this) - Number(sols); if (reste >= 0) { await Monnaie.optimiserFortune(this, reste); } @@ -3699,7 +3692,7 @@ export class RdDActor extends Actor { } else { const fromActor = game.actors.get(fromActorId) - await Monnaie.optimiserFortune(this, sols + this.getFortune()); + await Monnaie.optimiserFortune(this, sols + Monnaie.getFortune(this)); RdDAudio.PlayContextAudio("argent"); // Petit son ChatMessage.create({ @@ -3732,50 +3725,31 @@ export class RdDActor extends Actor { }); return; } - const acheteur = achat.acheteurId ? game.actors.get(achat.acheteurId) : undefined; - const vendeur = achat.vendeurId ? game.actors.get(achat.vendeurId) : undefined; - const vente = achat.vente; - const itemId = vente.item._id; - const isItemEmpilable = "quantite" in vente.item.system; const cout = Number(achat.prixTotal ?? 0); + const vente = achat.vente; + const acheteur = achat.acheteurId ? game.actors.get(achat.acheteurId) : undefined; + const vendeur = achat.vendeurId ? game.actors.get(achat.vendeurId) : undefined; + let itemVendu = vendeur?.getObjet(vente.item._id); + + if (vendeur && (itemVendu?.getQuantite() ?? 0) < achat.quantiteTotal) { + ChatUtility.notifyUser(achat.userId, 'warn', `Le vendeur n'a plus assez de ${vente.item.name} !`); + return; + } + if (Monnaie.getFortune(acheteur) < Number(cout)) { + ChatUtility.notifyUser(achat.userId, 'warn', `Vous n'avez pas assez d'argent pour payer ${Math.ceil(cout / 100)} sols !`); + return; + } + achat.quantiteTotal = (achat.choix.nombreLots ?? 1) * (vente.tailleLot); - if (acheteur) { - let resteAcheteur = await acheteur.depenserSols(cout); - if (resteAcheteur < 0) { - ChatUtility.notifyUser(achat.userId, 'warn', `Vous n'avez pas assez d'argent pour payer ${Math.ceil(cout / 100)} sols !`); - return; - } - } - const itemVendu = vendeur?.getObjet(itemId); - if (itemVendu) { - if (isItemEmpilable ? (itemVendu.system.quantite < achat.quantiteTotal) : (achat.choix.nombreLots != 1)) { - await acheteur?.ajouterSols(cout); - ChatUtility.notifyUser(achat.userId, 'warn', `Le vendeur n'a plus assez de ${vente.item.name} !`); - return; - } - vendeur.ajouterSols(cout); - let resteQuantite = (itemVendu.system.quantite ?? 1) - achat.quantiteTotal; - if (resteQuantite == 0) { - vendeur.deleteEmbeddedDocuments("Item", [itemId]) - } - else { - vendeur.updateEmbeddedDocuments("Item", [{ _id: itemId, 'system.quantite': resteQuantite }]); - } + if (vendeur) { + await vendeur.ajouterSols(cout); + await vendeur.decrementerQuantiteItem(itemVendu, achat.quantiteTotal,); } if (acheteur) { - const achatData = { - type: vente.item.type, - img: vente.item.img, - name: vente.item.name, - system: mergeObject(vente.item.system, { quantite: isItemEmpilable ? achat.quantiteTotal : undefined }), - } - let listeAchat = isItemEmpilable ? [achatData] : Array.from({ length: achat.quantiteTotal }, (_, i) => achatData) - let items = await acheteur.createEmbeddedDocuments("Item", listeAchat); - if (achat.choix.consommer && vente.item.type == 'nourritureboisson') { - achat.choix.doses = achat.choix.nombreLots; - await acheteur.consommerNourritureboisson(items[0].id, achat.choix, vente.actingUserId); - } + await acheteur.depenserSols(cout); + let createdItemId = await acheteur.creerQuantiteItem(vente.item, achat.quantiteTotal); + await acheteur.consommerNourritureAchetee(achat, vente, createdItemId); } if (cout > 0) { RdDAudio.PlayContextAudio("argent"); @@ -3804,6 +3778,42 @@ export class RdDActor extends Actor { } } + 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.getItemOfType(recetteId, 'recettealchimique'); diff --git a/module/dialog-split-item.js b/module/dialog-split-item.js index 4b21c6ef..20247353 100644 --- a/module/dialog-split-item.js +++ b/module/dialog-split-item.js @@ -12,7 +12,7 @@ export class DialogSplitItem extends Dialog { } constructor(item, splitData, html, callback) { - let options = { classes: ["dialogsplit"], width: 300, height: 160, 'z-index': 99999 }; + let options = { classes: ["dialogsplit"], width: 300, height: 'fit-content', 'z-index': 99999 }; let conf = { title: "Séparer en deux", content: html, diff --git a/module/item-monnaie.js b/module/item-monnaie.js index 7a16c258..24cea9ce 100644 --- a/module/item-monnaie.js +++ b/module/item-monnaie.js @@ -23,6 +23,7 @@ const MONNAIE_OR = { }; const MONNAIES_STANDARD = [MONNAIE_ETAIN, MONNAIE_BRONZE, MONNAIE_ARGENT, MONNAIE_OR]; +const VALEUR_DENIERS = sols => Math.max(Math.floor((sols ?? 0) * 100), 0); export class Monnaie { @@ -40,15 +41,11 @@ export class Monnaie { } static deValeur(monnaie, valeur) { - return Monnaie.valEntiere(valeur) == Monnaie.valEntiere(monnaie.system.cout) - } - - static valEntiere(sols) { - return Math.max(Math.floor((sols??0)*100), 0); + return VALEUR_DENIERS(valeur) == VALEUR_DENIERS(monnaie.system.cout) } static triValeurEntiere() { - return Misc.ascending(item => Monnaie.valEntiere(item.system.cout)) + return Misc.ascending(item => VALEUR_DENIERS(item.system.cout)) } static async creerMonnaiesStandard(actor) { @@ -65,29 +62,49 @@ export class Monnaie { return deniers; } + static getFortune(actor) { + if (actor) { + Monnaie.validerMonnaies(actor); + return actor.itemTypes['monnaie'] + .map(m => Number(m.system.cout) * Number(m.system.quantite)) + .reduce(Misc.sum(), 0); + } + return 0; + } + static async optimiserFortune(actor, fortune) { - let resteEnDeniers = Math.round(fortune*100); + let resteEnDeniers = Math.round(fortune * 100); let monnaies = actor.itemTypes['monnaie']; let updates = []; - let parValeur = Misc.classifyFirst(monnaies, it => Monnaie.valEntiere(it.system.cout)); - for (let valeurDeniers of [1000, 100, 10, 1]) { + Monnaie.validerMonnaies(actor); + + let parValeur = Misc.classifyFirst(monnaies, it => VALEUR_DENIERS(it.system.cout)); + for (let valeurDeniers of [1000, 100, 10, 1]) { const itemPiece = parValeur[valeurDeniers]; if (itemPiece) { const quantite = Math.floor(resteEnDeniers / valeurDeniers); if (quantite != itemPiece.system.quantite) { updates.push({ _id: parValeur[valeurDeniers].id, 'system.quantite': quantite }); } - resteEnDeniers -= quantite*valeurDeniers; + resteEnDeniers -= quantite * valeurDeniers; } } console.log('Monnaie.optimiserFortune', actor.name, 'total', fortune, 'parValeur', parValeur, 'updates', updates, 'reste', resteEnDeniers); if (updates.length > 0) { await actor.updateEmbeddedDocuments('Item', updates); } - if (resteEnDeniers > 0){ + if (resteEnDeniers > 0) { // créer le reste en deniers fortune en deniers await Monnaie.creerMonnaiesDeniers(actor, resteEnDeniers); } } + static validerMonnaies(actor) { + actor.itemTypes['monnaie'].filter(it => VALEUR_DENIERS(it.system.cout) == 0) + .map(it => `La monnaie ${it.name} de l'acteur ${actor.name} a une valeur de 0!`) + .forEach(message => { + ui.notifications.warn(message); + console.warn(message); + }); + } } diff --git a/module/item-sheet.js b/module/item-sheet.js index b928d36d..90ad5eb7 100644 --- a/module/item-sheet.js +++ b/module/item-sheet.js @@ -159,8 +159,6 @@ export class RdDItemSheet extends ItemSheet { super.activateListeners(html); this.html = html; - let itemSheetDialog = this; - HtmlUtility._showControlWhen(this.html.find(".item-cout"), ReglesOptionelles.isUsing('afficher-prix-joueurs') || game.user.isGM || !this.item.isOwned); HtmlUtility._showControlWhen(this.html.find(".item-magique"), this.item.isMagique()); @@ -178,6 +176,14 @@ export class RdDItemSheet extends ItemSheet { RdDUtility.checkThanatosXP(this.item.name); } }); + this.html.find(".item-cout input[name='system.cout']").change(event => { + if (this.item.isMonnaie()) { + const value = event.currentTarget.value; + if (Number(value) == 0) { + ui.notifications.error(`${this.actor?.name ?? 'Monnaie'}: La monnaie ${this.item.name} a maintenant une valeur de 0, et ne peut plus être utilisée pour payer!`) + } + } + }) this.html.find('.enchanteDate').change((event) => { let jour = Number(this.html.find('[name="splitDate.day"]').val()); @@ -201,12 +207,12 @@ export class RdDItemSheet extends ItemSheet { } }); - this.html.find('.item-split').click(async event => RdDSheetUtility.splitItem(RdDSheetUtility.getItem(event, this.actor), this.actor, async () => itemSheetDialog.render(true))); + this.html.find('.item-split').click(async event => RdDSheetUtility.splitItem(RdDSheetUtility.getItem(event, this.actor), this.actor, async () => this.render(true))); this.html.find('.item-edit').click(async event => RdDSheetUtility.getItem(event, this.actor)?.sheet.render(true)); this.html.find('.item-delete').click(async event => RdDUtility.confirmerSuppressionItem(this, RdDSheetUtility.getItem(event, this.actor))); this.html.find('.item-vendre').click(async event => RdDSheetUtility.getItem(event, this.actor)?.proposerVente()); this.html.find('.item-montrer').click(async event => RdDSheetUtility.getItem(event, this.actor)?.postItem()); - this.html.find('.item-action').click(async event => RdDSheetUtility.getItem(event, this.actor)?.actionPrincipale(this.actor, async () => itemSheetDialog.render(true))); + this.html.find('.item-action').click(async event => RdDSheetUtility.getItem(event, this.actor)?.actionPrincipale(this.actor, async () => this.render(true))); } _getEventActor(event) { diff --git a/module/item.js b/module/item.js index 4d888422..175bfaa8 100644 --- a/module/item.js +++ b/module/item.js @@ -149,6 +149,9 @@ export class RdDItem extends Item { isConteneur() { return this.type == 'conteneur'; } + isMonnaie() { + return this.type == 'monnaie'; + } getItemGroup() { if (this.isInventaire()) return "equipement"; diff --git a/styles/simple.css b/styles/simple.css index 66d8b5f8..32072afd 100644 --- a/styles/simple.css +++ b/styles/simple.css @@ -81,6 +81,7 @@ --background-custom-button: linear-gradient(to bottom, rgba(33, 55, 74, 0.988) 5%, rgba(21, 40, 51, 0.671) 100%); --background-custom-button-hover: linear-gradient(to bottom, rgb(128, 0, 0) 5%, rgb(62, 1, 1) 100%); --background-tooltip: rgba(220,220,210,0.95); + --background-error:hsla(16, 100%, 50%, 0.8); } /*@import url("https://fonts.googleapis.com/css2?family=Martel:wght@400;800&family=Roboto:wght@300;400;500&display=swap");*/ @@ -364,9 +365,21 @@ table {border: 1px solid #7a7971;} justify-content: center; text-align: left; } +.equipement-valeur { + margin: 0; + flex-grow: 1.5; + text-align: center; +} .equipement-detail { margin: 0; - flex: 'flex-shrink' ; + flex-grow: 1; + align-items: center; + justify-content: center; + text-align: center; +} +.equipement-button { + margin: 0; + flex-grow: 0.5; align-items: center; justify-content: center; text-align: center; @@ -879,6 +892,11 @@ ul, li { background: rgb(160, 130, 100, 0.05); } +input.attribute-value.field-error , +.list-item span.field-error { + background-color: var(--background-error); +} + ul.chat-list { margin-left: 0.8rem; list-style: inside; diff --git a/system.json b/system.json index ed3955d5..da9000c2 100644 --- a/system.json +++ b/system.json @@ -1,8 +1,8 @@ { "id": "foundryvtt-reve-de-dragon", "title": "Rêve de Dragon", - "version": "10.3.12", - "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-10.3.12.zip", + "version": "10.3.13", + "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-10.3.13.zip", "manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v10/system.json", "compatibility": { "minimum": "10", diff --git a/templates/actor/inventaire-monnaie.html b/templates/actor/inventaire-monnaie.html index 31498b52..f763d057 100644 --- a/templates/actor/inventaire-monnaie.html +++ b/templates/actor/inventaire-monnaie.html @@ -4,13 +4,16 @@
  • {{piece.name}} - + + ({{piece.system.cout}} Sols) + + {{piece.system.quantite}} - + diff --git a/templates/item/partial-inventaire.html b/templates/item/partial-inventaire.html index b05413fb..a8c8a5d6 100644 --- a/templates/item/partial-inventaire.html +++ b/templates/item/partial-inventaire.html @@ -14,7 +14,12 @@ {{#unless (isFieldInventaireModifiable type 'quantite')}}disabled{{/unless}}/>
    - + + {{#if (or (ne type 'monnaie') (gt system.cout 0))}} + {{else}} + + {{/if}}