import { RdDItemSort } from "./item-sort.js"; import { RdDUtility } from "./rdd-utility.js"; import { RdDAlchimie } from "./rdd-alchimie.js"; import { RdDItemCompetence } from "./item-competence.js"; import { RdDHerbes } from "./rdd-herbes.js"; import { RdDGemme } from "./rdd-gemme.js"; import { HtmlUtility } from "./html-utility.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { SYSTEM_RDD } from "./constants.js"; import { RdDSheetUtility } from "./rdd-sheet-utility.js"; import { SystemCompendiums } from "./settings/system-compendiums.js"; import { Misc } from "./misc.js"; import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDItemCompetenceCreature } from "./item-competencecreature.js"; import { ITEM_TYPES, RdDItem } from "./item.js"; import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js"; /** * Extend the basic ItemSheet for RdD specific items */ export class RdDItemSheet extends ItemSheet { static get ITEM_TYPE() { return undefined } static defaultTemplate(type) { return type ? `systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html` : "systems/foundryvtt-reve-de-dragon/templates/item-sheet.html"; } static register(sheetClass) { Items.registerSheet(SYSTEM_RDD, sheetClass, { label: Misc.typeName('Item', sheetClass.ITEM_TYPE), types: [sheetClass.ITEM_TYPE], makeDefault: true }) } /** @override */ static get defaultOptions() { return foundry.utils.mergeObject(super.defaultOptions, { classes: [SYSTEM_RDD, "sheet", "item"], template: RdDItemSheet.defaultTemplate(RdDItemSheet.ITEM_TYPE), width: 550, height: 550 }, { inplace: false }); } /* -------------------------------------------- */ get template() { return RdDItemSheet.defaultTemplate(this.item.type); } get title() { const owner = (this.item.parent instanceof Actor) ? `(${this.item.parent.name})` : ''; return `${Misc.typeName('Item', this.item.type)}: ${this.item.name} ${owner}`; } /* -------------------------------------------- */ _getHeaderButtons() { let buttons = super._getHeaderButtons(); if (this.item.isInventaire() && this.item.isVideOuNonConteneur()) { buttons.unshift({ class: "vendre", icon: "fas fa-comments-dollar", onclick: ev => this.item.proposerVente(1) }); } buttons.unshift({ class: "montrer", icon: "fas fa-comment", onclick: ev => this.item.postItemToChat() }); return buttons } /* -------------------------------------------- */ /** @override */ setPosition(options = {}) { const position = super.setPosition(options); const sheetHeader = this.element.find(".sheet-header"); const sheetBody = this.element.find(".sheet-body"); const bodyHeight = position.height - sheetHeader[0].clientHeight; sheetBody.css("height", bodyHeight); return position; } /* -------------------------------------------- */ async getData() { let formData = { title: this.item.name, id: this.item.id, type: this.item.type, img: this.item.img, name: this.item.name, system: this.item.system, actorId: this.actor?.id, description: await TextEditor.enrichHTML(this.item.system.description, { async: true }), descriptionmj: await TextEditor.enrichHTML(this.item.system.descriptionmj, { async: true }), isComestible: this.item.getUtilisationCuisine(), options: RdDSheetUtility.mergeDocumentRights(this.options, this.item, this.isEditable), competences: await SystemCompendiums.getCompetences('personnage'), categories: RdDItem.getCategories(this.item.type), } if (this.item.type == ITEM_TYPES.competencecreature) { formData.isparade = RdDItemCompetenceCreature.isParade(this.item) formData.isdommages = RdDItemCompetenceCreature.isDommages(this.item) } if (this.item.type == ITEM_TYPES.tache || this.item.type == ITEM_TYPES.livre || this.item.type == ITEM_TYPES.meditation || this.item.type == ITEM_TYPES.oeuvre) { formData.caracList = foundry.utils.duplicate(game.model.Actor.personnage.carac) formData.caracList["reve-actuel"] = foundry.utils.duplicate(game.model.Actor.personnage.reve.reve) } if (this.item.type == ITEM_TYPES.arme) { formData.competences = formData.competences.filter(it => it.isCompetenceArme()) } if (this.item.type == ITEM_TYPES.recettecuisine) { formData.ingredients = await TextEditor.enrichHTML(this.object.system.ingredients, { async: true }) } if (this.item.type == ITEM_TYPES.extraitpoetique) { formData.extrait = await TextEditor.enrichHTML(this.object.system.extrait, { async: true }) formData.texte = await TextEditor.enrichHTML(this.object.system.texte, { async: true }) } if (this.item.type == ITEM_TYPES.recettealchimique) { RdDAlchimie.processManipulation(this.item, this.actor?.id); formData.manipulation_update = await TextEditor.enrichHTML(this.object.system.manipulation_update, { async: true }) formData.utilisation = await TextEditor.enrichHTML(this.object.system.utilisation, { async: true }) formData.enchantement = await TextEditor.enrichHTML(this.object.system.enchantement, { async: true }) formData.sureffet = await TextEditor.enrichHTML(this.object.system.sureffet, { async: true }) } if (this.item.type == ITEM_TYPES.gemme) { formData.gemmeTypeList = RdDGemme.getGemmeTypeOptionList(); RdDGemme.calculDataDerivees(this.item) } if (this.item.type == ITEM_TYPES.potion) { RdDHerbes.calculFormData(formData, this.item) } if (this.item.type == ITEM_TYPES.herbe) { if (formData.options.isOwned && ['Soin', 'Repos'].includes(formData.system.categorie)) { formData.isIngredientPotionBase = true; } } if (this.item.type == ITEM_TYPES.sortreserve) { const sortId = this.item.system.sortid; formData.competences = formData.competences.filter(it => RdDItemCompetence.isDraconic(it)); formData.sort = formData.options.isOwned ? this.item.actor.items.get(sortId) : game.items.get(sortId); } if (this.item.type == ITEM_TYPES.sort) { formData.competences = formData.competences.filter(it => RdDItemCompetence.isDraconic(it)); formData.bonusCaseList = RdDItemSort.getBonusCaseList(this.item); } return formData; } /* -------------------------------------------- */ /** @override */ activateListeners(html) { super.activateListeners(html); this.html = html; HtmlUtility.showControlWhen(this.html.find(".item-cout"), ReglesOptionnelles.isUsing('afficher-prix-joueurs') || game.user.isGM || !this.item.isOwned); HtmlUtility.showControlWhen(this.html.find(".item-magique"), this.item.isMagique()); // Everything below here is only needed if the sheet is editable if (!this.options.editable) return; this.form.ondragstart = (event) => this._onDragStart(event); this.form.ondrop = (event) => this._onDrop(event); // Select competence categorie this.html.find(".categorie").change(event => this._onSelectCategorie(event)); this.html.find('.sheet-competence-xp').change((event) => { if (this.item.isCompetencePersonnage()) { 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('.delete-bonus-case').click((event) => { this.supprimerBonusCase(event.currentTarget.attributes['data-deleteCoord'].value) }) this.html.find('.date-enchantement').change((event) => { const jour = Number(this.html.find('input.date-enchantement[name="enchantement.jour"]').val()); const mois = RdDTimestamp.definition(this.html.find('select.date-enchantement[name="enchantement.mois"]').val()); const indexDate = game.system.rdd.calendrier.getIndexFromDate(jour, mois.heure); this.item.update({ 'system.prdate': indexDate }); console.warn(`Date d'enchantement modifiée ${jour}/${mois.heure}: ${indexDate}`) }); this.html.find('.creer-tache-livre').click((event) => this._getEventActor(event).creerTacheDepuisLivre(this.item)); this.html.find('.consommer-potion').click((event) => this._getEventActor(event).consommerPotion(this.item, this.getActionRenderItem())); this.html.find('.creer-potion-base').click((event) => this._getEventActor(event).actionHerbe(this.item)); this.html.find('input[name="system.cacher_points_de_tache"]').change(async event => await this.item.update({ 'system.cacher_points_de_tache': event.currentTarget.checked })); this.html.find('.alchimie-tache a').click((event) => { let actor = this._getEventActor(event); if (actor) { let recetteId = event.currentTarget.attributes['data-recette-id'].value; let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value; let tacheData = event.currentTarget.attributes['data-alchimie-data'].value; actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData); } else { ui.notifications.info("Impossible trouver un acteur pour réaliser cette tache Alchimique."); } }); if (this.actor) { this.html.find('.item-split').click(async event => RdDSheetUtility.splitItem(RdDSheetUtility.getItem(event, this.actor), this.actor, this.getActionRenderItem())); 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.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-montrer').click(async event => RdDSheetUtility.getItem(event, this.actor)?.postItemToChat()); this.html.find('.item-action').click(async event => RdDSheetUtility.getItem(event, this.actor)?.actionPrincipale(this.actor, this.getActionRenderItem())); this.html.find('.item-quantite-plus').click(async event => { await this.actor.itemQuantiteIncDec(RdDSheetUtility.getItemId(event), 1) this.render(); }); this.html.find('.item-quantite-moins').click(async event => { await this.actor.itemQuantiteIncDec(RdDSheetUtility.getItemId(event), -1) this.render(); }); } const updateItemTimestamp = (path, timestamp) => this.item.update({ [path]: foundry.utils.duplicate(timestamp) }) RdDTimestamp.handleTimestampEditor(this.html, 'system.temporel.debut', updateItemTimestamp); RdDTimestamp.handleTimestampEditor(this.html, 'system.temporel.fin', updateItemTimestamp); } getActionRenderItem() { return async () => { let item = this.item; while (item) { await item.sheet?.render() item = this.actor.getContenant(item) } } } _getEventActor(event) { let actorId = event.currentTarget.attributes['data-actor-id'].value; let actor = game.actors.get(actorId); return actor; } /* -------------------------------------------- */ async _onSelectCategorie(event) { event.preventDefault(); if (this.item.isCompetence()) { const categorie = event.currentTarget.value; const level = RdDItemCompetence.getNiveauBase(categorie, this.item.type); this.item.system.base = level; this.html.find('[name="system.base"]').val(level); } } async supprimerBonusCase(deleteCoord){ if (this.item.type == ITEM_TYPES.sort) { const oldList = RdDItemSort.getBonusCaseList(this.item) const newList = oldList.filter(it => it.case != deleteCoord); if (newList.length != oldList.length) { await this.item.update({ 'system.bonuscase': RdDItemSort.bonuscasesToString(newList) }) } } } /* -------------------------------------------- */ /** @override */ _updateObject(event, formData) { switch (this.item.type) { case ITEM_TYPES.sort: formData['system.bonuscase'] = RdDItemSort.bonuscasesToString(RdDItemSheet._listCaseTmr( formData.caseTmrCoord, formData.caseTmrBonus, formData.caseTmrAdd )) break case ITEM_TYPES.competence: formData['system.niveau'] = formData['system.niveau'] ?? formData['system.base'] break } return this.item.update(formData); } /* -------------------------------------------- */ /** * reconstruit les bonus de cases * @param {*} caseTmrCoord tableau des coordonées * @param {*} caseTmrBonus tableau des bonus * @param {*} caseTmrAdd case à ajouter * @returns list d'objets {coord, bonus} */ static _listCaseTmr(caseTmrCoord, caseTmrBonus, caseTmrAdd) { const listCaseTmrCoord = caseTmrCoord == undefined ? [] : Array.isArray(caseTmrCoord) ? caseTmrCoord : [caseTmrCoord] const listCaseTmrBonus = caseTmrBonus == undefined ? [] : Array.isArray(caseTmrBonus) ? caseTmrBonus : [caseTmrBonus] if (caseTmrAdd != undefined && caseTmrAdd != '' && TMRUtility.verifyTMRCoord(caseTmrAdd) && !listCaseTmrCoord.includes(caseTmrAdd)) { listCaseTmrCoord.push(TMRUtility.getTMR(caseTmrAdd).coord) listCaseTmrBonus.push(1) } const list = []; const caseChecked = {}; for (let i = 0; i < listCaseTmrBonus.length && i < listCaseTmrCoord.length; i++) { const coord = listCaseTmrCoord[i] == FLEUVE_COORD ? FLEUVE_COORD : (listCaseTmrCoord[i]?.toUpperCase() ?? 'A1') const bonus = listCaseTmrBonus[i] ?? 0 if (TMRUtility.verifyTMRCoord(coord) && bonus >= 0 && !caseChecked[coord]) { caseChecked[coord] = coord list.push({ case: coord, bonus: bonus }) } } return list } /* -------------------------------------------- */ async _onDragStart(event) { } async _onDrop(event) { // Try to extract the dragData let dragData = RdDItemSheet.$extractDragData(event); if (!dragData) return false; const allowed = Hooks.call("dropActorSheetData", this.actor, this, dragData); if (allowed === false) return false; // Handle different dragData types switch (dragData.type) { case "Item": return this._onDropItem(event, dragData); case "Actor": return this._onDropActor(event, dragData); } return super._onDrop(event); } static $extractDragData(event) { try { const eventData = event?.dataTransfer?.getData('text/plain'); if (eventData) { return JSON.parse(eventData); } } catch (err) { } return undefined; } async _onDropItem(event, dragData) { } async _onDropActor(event, dragData) { } }