import { DialogItemVente } from "./dialog-item-vente.js"; import { Grammar } from "./grammar.js"; import { Misc } from "./misc.js"; import { RdDUtility } from "./rdd-utility.js"; const typesObjetsEquipement = ["objet", "arme", "armure", "gemme", "conteneur", "herbe", "ingredient", "livre", "potion", "munition", "nourritureboisson", "monnaie"]; const typesObjetsOeuvres = ["oeuvre", "recettecuisine", "musique", "chant", "danse", "jeu"]; const encBrin = 0.00005;// un brin = 1 décigramme = 1/10g = 1/10000kg = 1/20000 enc export const defaultItemImg = { competence: "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp", compcreature: "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp", arme: "systems/foundryvtt-reve-de-dragon/icons/armes_armures/epee_gnome.webp", armure: "systems/foundryvtt-reve-de-dragon/icons/armes_armures/armure_plaques.webp", conteneur: "systems/foundryvtt-reve-de-dragon/icons/objets/sac_a_dos.webp", sort: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp", herbe: "systems/foundryvtt-reve-de-dragon/icons/botanique/Endorlotte.png", ingredient: "systems/foundryvtt-reve-de-dragon/icons/objets/sable_poudre.webp", livre: "systems/foundryvtt-reve-de-dragon/icons/objets/livre.webp", potion: "systems/foundryvtt-reve-de-dragon/icons/objets/liqueur_de_bagdol.webp", queue: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp", ombre: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp", souffle: "systems/foundryvtt-reve-de-dragon/icons/souffle_dragon.webp", tete: "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp", meditation: "systems/foundryvtt-reve-de-dragon/icons/meditations_ecrits/meditation_alchimie.webp", recettealchimique: "systems/foundryvtt-reve-de-dragon/icons/competence_alchimie.webp", chant: "systems/foundryvtt-reve-de-dragon/icons/arts/chant_0.webp", danse: "systems/foundryvtt-reve-de-dragon/icons/arts/danse_0.webp", jeu: "systems/foundryvtt-reve-de-dragon/icons/arts/jeux_petasse.webp", recettecuisine: "systems/foundryvtt-reve-de-dragon/icons/arts/recette_cuisine_1.webp", musique: "systems/foundryvtt-reve-de-dragon/icons/arts/chant_0.webp", maladie: "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/maladie.webp", 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", signedraconique: "systems/foundryvtt-reve-de-dragon/icons/tmr/signe_draconique.webp", gemme: "systems/foundryvtt-reve-de-dragon/icons/gemmes/almaze.webp" } /* -------------------------------------------- */ export class RdDItem extends Item { constructor(data, context) { if (!data.img) { data.img = defaultItemImg[data.type]; } super(data, context); } static getTypeObjetsEquipement() { return typesObjetsEquipement; } static getTypesOeuvres() { return typesObjetsOeuvres; } isCompetence() { return Misc.data(this).type == 'competence'; } isConteneur() { return Misc.data(this).type == 'conteneur'; } isVide() { return this.isConteneur() && (Misc.templateData(this).contenu ?? []).length == 0; } isAlcool() { const itemData = Misc.data(this); return itemData.type == 'nourritureboisson' && itemData.data.boisson && itemData.data.alcoolise; } isPotion() { return Misc.data(this).type == 'potion'; } isEquipement() { return RdDItem.getTypeObjetsEquipement().includes(Misc.data(this).type); } isCristalAlchimique() { const itemData = Misc.data(this); return itemData.type == 'objet' && Grammar.toLowerCaseNoAccent(itemData.name) == 'cristal alchimique' && itemData.data.quantite > 0; } isMagique() { return Misc.templateData(this).magique; } getEncTotal() { const itemData = Misc.data(this); return Number(itemData.data.encombrement ?? 0) * Number(itemData.data.quantite ?? 1); } getEnc() { const itemData = Misc.data(this); switch (itemData.type) { case 'herbe': return encBrin; } return itemData.data.encombrement ?? 0; } prepareDerivedData() { super.prepareDerivedData(); if (this.isEquipement(this)) { this._calculsEquipement(); } if (this.isPotion()) { this.prepareDataPotion() } const itemData = Misc.data(this); itemData.data.actionPrincipale = this.getActionPrincipale({ warnIfNot: false }); } prepareDataPotion() { const tplData = Misc.templateData(this); const categorie = Grammar.toLowerCaseNoAccent(tplData.categorie); tplData.magique = categorie.includes('enchante'); if (tplData.magique) { if (categorie.includes('soin') || categorie.includes('repos')) { tplData.puissance = tplData.herbebonus * tplData.pr; } } } _calculsEquipement() { const tplData = Misc.templateData(this); const quantite = this.isConteneur() ? 1 : (tplData.quantite ?? 0); const enc = this.getEnc(); if (enc != undefined) { tplData.encTotal = Math.max(enc, 0) * quantite; } if (tplData.cout != undefined) { tplData.prixTotal = Math.max(tplData.cout, 0) * quantite; } } getActionPrincipale(options = { warnIfNot: true }) { const itemData = Misc.data(this); if ((itemData.data.quantite ?? 0) <= 0) { if (options.warnIfNot) { ui.notifications.warn(`Vous n'avez plus de ${itemData.name}.`); } return undefined; } switch (itemData.type) { case 'nourritureboisson': return itemData.data.boisson ? 'Boire' : 'Manger'; case 'potion': return 'Boire'; case 'livre': return 'Lire'; } if (options.warnIfNot) { ui.notifications.warn(`Impossible d'utilise un ${itemData.name}, aucune action associée définie.`); } return undefined; } async diminuerQuantite(nombre, options = { diminuerQuantite: true, supprimerSiZero: false }) { if (options.diminuerQuantite == false) return; await this.quantiteIncDec(-nombre, options); } async quantiteIncDec(nombre, options = { diminuerQuantite: true, supprimerSiZero: false }) { const itemData = Misc.data(this); const quantite = Number(itemData.data.quantite ?? -1); if (quantite >= 0) { const reste = Math.max(quantite + Number(nombre), 0); if (reste == 0) { if (options.supprimerSiZero) { ui.notifications.notify(`${itemData.name} supprimé de votre équipement`); await this.delete(); } else { ui.notifications.notify(`Il ne vous reste plus de ${itemData.name}, vous pouvez le supprimer de votre équipement, ou trouver un moyen de vous en procurer.`); await this.update({ "data.quantite": 0 }); } } else { await this.update({ "data.quantite": reste }); } } } /* -------------------------------------------- */ // détermine si deux équipements sont similaires: de même type, et avec les même champs hormis la quantité isEquipementSimilaire(other) { const itemData = Misc.data(this); const otherData = Misc.data(other); const tplData = Misc.templateData(this); const otherTplData = Misc.templateData(other); if (!this.isEquipement()) return false; if (itemData.type != otherData.type) return false; if (itemData.name != otherData.name) return false; if (tplData.quantite == undefined) return false; const differences = Object.entries(tplData).filter(([key, value]) => !['quantite', 'encTotal', 'prixTotal', 'cout'].includes(key)) .filter(([key, value]) => value != otherTplData[key]); if (differences.length > 0) { let message = `Impossible de regrouper les ${itemData.type} ${itemData.name}: `; for (const [key, value] of differences){ message += `
${key}: ${value} vs ${otherTplData[key]}`; } ui.notifications.info(message) return false; } return true; } async proposerVente() { console.log(this); const dialog = await DialogItemVente.create(this, (vente) => this._onProposerVente(vente)) dialog.render(true); } async _onProposerVente(venteData) { venteData["properties"] = this.getProprietes(); if (venteData.isOwned) { if (venteData.quantiteNbLots * venteData.tailleLot > venteData.quantiteMax) { ui.notifications.warn(`Vous avez ${venteData.quantiteMax} ${venteData.item.name}, ce n'est pas suffisant pour vendre ${venteData.quantiteNbLots} de ${venteData.tailleLot}`) return; } } venteData.jsondata = JSON.stringify(venteData.item); console.log(venteData); let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', venteData); ChatMessage.create(RdDUtility.chatDataSetup(html)); } /* -------------------------------------------- */ getProprietes() { return this[`_${Misc.data(this).type}ChatData`](); } /* -------------------------------------------- */ async postItem( modeOverride ) { console.log(this); let chatData = duplicate(Misc.data(this)); const properties = this.getProprietes(); chatData["properties"] = properties if (this.actor) { chatData.actor = { id: this.actor.id }; } //Check if the posted item should have availability/pay buttons chatData.hasPrice = "cout" in chatData.data; chatData.data.cout_deniers = 0; let dialogResult = [-1, -1]; // dialogResult[0] = quantité, dialogResult[1] = prix if (chatData.hasPrice) { chatData.data.cout_deniers = Math.floor(chatData.data.cout * 100); dialogResult = await new Promise((resolve, reject) => { new Dialog({ content: `

Modifier la quantité?

Modifier la prix?

`, title: "Quantité & Prix", buttons: { post: { label: "Soumettre", callback: (dlg) => { resolve([Number(dlg.find('[name="quantity"]').val()), Number(dlg.find('[name="price"]').val())]) } }, } }).render(true) }) } let quantiteEnvoi = this.isOwned ? Math.min(dialogResult[0], chatData.data.quantite) : dialogResult[0]; const prixTotal = dialogResult[1]; if (quantiteEnvoi > 0) { if (this.isOwned) { if (chatData.data.quantite == 0) { quantiteEnvoi = -1 } else if (quantiteEnvoi > chatData.data.quantite) { quantiteEnvoi = chatData.data.quantite; ui.notifications.notify(`Impossible de poster plus que ce que vous avez. La quantité à été réduite à ${quantiteEnvoi}.`) } if (quantiteEnvoi > 0) { this.diminuerQuantite(quantiteEnvoi); } } } if (chatData.hasPrice) { if (quantiteEnvoi > 0) chatData.postQuantity = Number(quantiteEnvoi); if (prixTotal >= 0) { chatData.postPrice = prixTotal; chatData.data.cout_deniers = Math.floor(prixTotal * 100); // Mise à jour cout en deniers } chatData.finalPrice = Number(chatData.postPrice) * Number(chatData.postQuantity); chatData.data.cout_deniers_total = chatData.data.cout_deniers * Number(chatData.postQuantity); chatData.data.quantite = chatData.postQuantity; console.log("POST : ", chatData.finalPrice, chatData.data.cout_deniers_total, chatData.postQuantity); } // Don't post any image for the item (which would leave a large gap) if the default image is used if (chatData.img.includes("/blank.png")) chatData.img = null; // JSON object for easy creation chatData.jsondata = JSON.stringify( { compendium: "postedItem", payload: chatData, }); renderTemplate('systems/foundryvtt-reve-de-dragon/templates/post-item.html', chatData).then(html => { let chatOptions = RdDUtility.chatDataSetup(html, modeOverride); ChatMessage.create(chatOptions) }); } static propertyIfDefined(name, val, condition = (it) => true) { return condition ? [`${name}: ${val}`] : []; } /* -------------------------------------------- */ _objetChatData() { const tplData = Misc.templateData(this); let properties = [].concat( RdDItem.propertyIfDefined('Résistance', tplData.resistance, tplData.resistance), RdDItem.propertyIfDefined('Qualité', tplData.qualite, tplData.qualite), RdDItem.propertyIfDefined('Encombrement', tplData.encombrement), ); return properties; } /* -------------------------------------------- */ _nourritureboissonChatData() { const tplData = Misc.templateData(this); let properties = [].concat( RdDItem.propertyIfDefined('Sustentation', tplData.sust, tplData.sust > 0), RdDItem.propertyIfDefined('Désaltère', tplData.desaltere, tplData.boisson), RdDItem.propertyIfDefined('Force alcool', tplData.force, tplData.boisson && tplData.alcoolise), RdDItem.propertyIfDefined('Exotisme', tplData.exotisme, tplData.exotisme < 0), RdDItem.propertyIfDefined('Qualité', tplData.qualite, tplData.qualite), RdDItem.propertyIfDefined('Encombrement', tplData.encombrement), ); return properties; } /* -------------------------------------------- */ _armeChatData() { const tplData = Misc.templateData(this); let properties = [ `Compétence: ${tplData.competence}`, `Dommages: ${tplData.dommages}`, `Force minimum: ${tplData.force}`, `Resistance: ${tplData.resistance}`, `Encombrement: ${tplData.encombrement}` ] return properties; } /* -------------------------------------------- */ _conteneurChatData() { const tplData = Misc.templateData(this); let properties = [ `Capacité: ${tplData.capacite} Enc.`, `Encombrement: ${tplData.encombrement}` ] return properties; } /* -------------------------------------------- */ _munitionChatData() { const tplData = Misc.templateData(this); let properties = [ `Encombrement: ${tplData.encombrement}` ] return properties; } /* -------------------------------------------- */ _armureChatData() { const tplData = Misc.templateData(this); let properties = [ `Protection: ${tplData.protection}`, `Détérioration: ${tplData.deterioration}`, `Malus armure: ${tplData.malus}`, `Encombrement: ${tplData.encombrement}` ] return properties; } /* -------------------------------------------- */ _competenceChatData() { const tplData = Misc.templateData(this); let properties = [ `Catégorie: ${tplData.categorie}`, `Niveau: ${tplData.niveau}`, `Caractéristique par défaut: ${tplData.carac_defaut}`, `XP: ${tplData.xp}` ] return properties; } /* -------------------------------------------- */ _competencecreatureChatData() { const tplData = Misc.templateData(this); let properties = [ `Catégorie: ${tplData.categorie}`, `Niveau: ${tplData.niveau}`, `Caractéristique: ${tplData.carac_value}`, `XP: ${tplData.xp}` ] return properties; } /* -------------------------------------------- */ _sortChatData() { const tplData = Misc.templateData(this); let properties = [ `Draconic: ${tplData.draconic}`, `Difficulté: ${tplData.difficulte}`, `Case TMR: ${tplData.caseTMR}`, `Points de Rêve: ${tplData.ptreve}` ] return properties; } /* -------------------------------------------- */ _herbeChatData() { const tplData = Misc.templateData(this); let properties = [ `Milieu: ${tplData.milieu}`, `Rareté: ${tplData.rarete}`, `Catégorie: ${tplData.categorie}`, ] return properties; } /* -------------------------------------------- */ _ingredientChatData() { const tplData = Misc.templateData(this); let properties = [ `Milieu: ${tplData.milieu}`, `Rareté: ${tplData.rarete}`, `Catégorie: ${tplData.categorie}`, ] return properties; } /* -------------------------------------------- */ _tacheChatData() { const tplData = Misc.templateData(this); let properties = [ `Caractéristique: ${tplData.carac}`, `Compétence: ${tplData.competence}`, `Périodicité: ${tplData.periodicite}`, `Fatigue: ${tplData.fatigue}`, `Difficulté: ${tplData.difficulte}`, `Points de Tâche: ${tplData.points_de_tache}`, `Points de Tâche atteints: ${tplData.points_de_tache_courant}` ] return properties; } /* -------------------------------------------- */ _livreChatData() { const tplData = Misc.templateData(this); let properties = [ `Compétence: ${tplData.competence}`, `Auteur: ${tplData.auteur}`, `Difficulté: ${tplData.difficulte}`, `Points de Tâche: ${tplData.points_de_tache}`, `Encombrement: ${tplData.encombrement}` ] return properties; } /* -------------------------------------------- */ _potionChatData() { const tplData = Misc.templateData(this); let properties = [ `Rareté: ${tplData.rarete}`, `Catégorie: ${tplData.categorie}`, `Encombrement: ${tplData.encombrement}`, ] return properties; } /* -------------------------------------------- */ _queueChatData() { const tplData = Misc.templateData(this); let properties = [ `Refoulement: ${tplData.refoulement}` ] return properties; } /* -------------------------------------------- */ _ombreChatData() { const tplData = Misc.templateData(this); let properties = [ `Refoulement: ${tplData.refoulement}` ] return properties; } /* -------------------------------------------- */ _souffleChatData() { const tplData = Misc.templateData(this); let properties = []; return properties; } /* -------------------------------------------- */ _teteChatData() { const tplData = Misc.templateData(this); let properties = []; return properties; } /* -------------------------------------------- */ _tarotChatData() { const tplData = Misc.templateData(this); let properties = [ `Concept: ${tplData.concept}`, `Aspect: ${tplData.aspect}`, ] return properties; } /* -------------------------------------------- */ _nombreastralChatData() { const tplData = Misc.templateData(this); let properties = [ `Valeur: ${tplData.value}`, `Jour: ${tplData.jourlabel}`, ] return properties; } /* -------------------------------------------- */ _monnaieChatData() { const tplData = Misc.templateData(this); let properties = [ `Valeur en Deniers: ${tplData.valeur_deniers}`, `Encombrement: ${tplData.encombrement}` ] return properties; } /* -------------------------------------------- */ _meditationChatData() { const tplData = Misc.templateData(this); let properties = [ `Thème: ${tplData.theme}`, `Compétence: ${tplData.competence}`, `Support: ${tplData.support}`, `Heure: ${tplData.heure}`, `Purification: ${tplData.purification}`, `Vêture: ${tplData.veture}`, `Comportement: ${tplData.comportement}`, `Case TMR: ${tplData.tmr}` ] return properties; } /* -------------------------------------------- */ _casetmrChatData() { const tplData = Misc.templateData(this); let properties = [ `Coordonnée: ${tplData.coord}`, `Spécificité: ${tplData.specific}` ] return properties; } /* -------------------------------------------- */ _maladieChatData() { const tplData = Misc.templateData(this); let properties if (tplData.identifie) { properties = [ `Malignité: ${tplData.malignite}`, `Périodicité: ${tplData.periodicite}`, `Dommages: ${tplData.dommages}` ] if (tplData.remedesconnus) { properties.push(`Remedes: ${tplData.remedes}` ) } } else { properties = [ `Inconnue` ] } return properties; } /* -------------------------------------------- */ _poisonChatData() { return this._maladieChatData(); } /* -------------------------------------------- */ _gemmeChatData() { const tplData = Misc.templateData(this); let properties = [ `Pureté: ${tplData.purete}`, `Taille: ${tplData.taille}`, `Inertie: ${tplData.inertie}`, `Enchantabilité: ${tplData.enchantabilite}`, `Prix: ${tplData.cout}`, ] return properties; } }