/* Common useful functions shared between objects */ import { ChatUtility } from "./chat-utility.js"; import { RdDCombat } from "./rdd-combat.js"; import { Misc } from "./misc.js"; import { Grammar } from "./grammar.js"; import { TMRUtility } from "./tmr-utility.js"; import { DialogItemAchat } from "./achat-vente/dialog-item-achat.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { RdDDice } from "./rdd-dice.js"; import { RdDItem } from "./item.js"; import { RdDPossession } from "./rdd-possession.js"; import { RdDNameGen } from "./rdd-namegen.js"; import { RdDConfirm } from "./rdd-confirm.js"; import { RdDItemCompetence } from "./item-competence.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDRaretes } from "./item/raretes.js"; import { RdDEmpoignade } from "./rdd-empoignade.js"; import { ExperienceLog } from "./actor/experience-log.js"; import { RdDCoeur } from "./coeur/rdd-coeur.js"; import { APP_ASTROLOGIE_REFRESH } from "./sommeil/app-astrologie.js"; import { RDD_CONFIG } from "./constants.js"; /* -------------------------------------------- */ // This table starts at 0 -> niveau -10 const carac_array = ["taille", "apparence", "constitution", "force", "agilite", "dexterite", "vue", "ouie", "odoratgout", "volonte", "intellect", "empathie", "reve", "chance", "melee", "tir", "lancer", "derobee"]; const difficultesLibres = Misc.intArray(0, -11); const ajustementsConditions = Misc.intArray(-10, 11); const ajustementsEncaissement = Misc.intArray(-10, 26); /* -------------------------------------------- */ function _buildAllSegmentsFatigue(max) { const cycle = [5, 2, 4, 1, 3, 0]; const fatigue = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]; for (let i = 0; i <= max; i++) { const ligneFatigue = foundry.utils.duplicate(fatigue[i]); const caseIncrementee = cycle[i % 6]; ligneFatigue[caseIncrementee]++; ligneFatigue[caseIncrementee + 6]++; ligneFatigue.fatigueMax = 2 * (i + 1); fatigue[i + 1] = ligneFatigue; } return fatigue; } /* -------------------------------------------- */ function _cumulSegmentsFatigue(matrix) { let cumulMatrix = []; for (let line of matrix) { let cumul = foundry.utils.duplicate(line); for (let i = 1; i < 12; i++) { cumul[i] += cumul[i - 1]; } cumulMatrix.push(cumul); } return cumulMatrix; } /* -------------------------------------------- */ export const MAX_ENDURANCE_FATIGUE = 60; const fatigueMatrix = _buildAllSegmentsFatigue(MAX_ENDURANCE_FATIGUE); const cumulFatigueMatrix = _cumulSegmentsFatigue(fatigueMatrix); const fatigueMalus = [0, 0, 0, -1, -1, -1, -2, -3, -4, -5, -6, -7]; // Provides the malus for each segment of fatigue const fatigueLineSize = [3, 6, 7, 8, 9, 10, 11, 12]; const fatigueLineMalus = [0, -1, -2, -3, -4, -5, -6, -7]; /* -------------------------------------------- */ const nomEthylisme = ["Emeché", "Gris", "Pinté", "Pas frais", "Ivre", "Bu", "Complètement fait", "Ivre mort"]; /* -------------------------------------------- */ const definitionsEncaissement = { "mortel": [ { minimum: undefined, maximum: 0, endurance: "0", vie: "0", gravite: -1 }, { minimum: 1, maximum: 10, endurance: "1d4", vie: "0", gravite: 0 }, { minimum: 11, maximum: 15, endurance: "1d6", vie: "0", gravite: 2 }, { minimum: 16, maximum: 19, endurance: "2d6", vie: "2", gravite: 4 }, { minimum: 20, maximum: undefined, endurance: "100", vie: "4 + @over20", gravite: 6 }, ], "non-mortel": [ { minimum: undefined, maximum: 0, endurance: "0", vie: "0", gravite: -1 }, { minimum: 1, maximum: 10, endurance: "1d4", vie: "0", gravite: 0 }, { minimum: 11, maximum: 15, endurance: "1d6", vie: "0", gravite: 0 }, { minimum: 16, maximum: 19, endurance: "2d6", vie: "0", gravite: 2 }, { minimum: 20, maximum: undefined, endurance: "100", vie: "0", gravite: 2 }, ], "entiteincarnee": [ { minimum: undefined, maximum: 0, endurance: "0", vie: "0", gravite: -1 }, { minimum: 1, maximum: 10, endurance: "1d4", vie: "0", gravite: 0 }, { minimum: 11, maximum: 15, endurance: "1d6", vie: "0", gravite: 0 }, { minimum: 16, maximum: 19, endurance: "2d6", vie: "0", gravite: 0 }, { minimum: 20, maximum: undefined, endurance: "3d6 + @over20", vie: "0", gravite: 0 }, ] }; /* -------------------------------------------- */ export class RdDUtility { // persistent handling of conteneur show/hide static afficheContenu = {} /* -------------------------------------------- */ static async init() { Hooks.on("renderChatMessage", async (app, html, msg) => await ChatUtility.onRenderChatMessage(app, html, msg)) Hooks.on("createChatMessage", async (chatMessage, options, id) => await ChatUtility.onCreateChatMessage(chatMessage, options, id)) Hooks.on('renderChatLog', (log, html, chatLog) => RdDUtility.chatListeners(html)) } /* -------------------------------------------- */ static async preloadHandlebarsTemplates() { const templatePaths = [ //Character Sheets 'systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/actor-creature-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/actor-vehicule-sheet.html', // sous-parties de feuilles de personnages 'systems/foundryvtt-reve-de-dragon/templates/actor/header-buttons.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/header-etat.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/header-compteurs.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/header-compteurs-creature.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/header-compteurs-entitee.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/header-effects.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/header-hautreve.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/archetype.hbs', 'systems/foundryvtt-reve-de-dragon/templates/actor/vue-detaillee.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/carac-main.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/carac-derivee.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/carac-creature.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/carac-entitee.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/comp-creature.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/comp-possession.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/carac-total.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/competence.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/competence-categorie.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/xp-competences.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/combat.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/blessures.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/blessure.hbs', 'systems/foundryvtt-reve-de-dragon/templates/actor/maladies-poisons.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/possessions.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/resonances.hbs', 'systems/foundryvtt-reve-de-dragon/templates/actor/taches.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/taches.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/oeuvres.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/oeuvre.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/jeux.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/alchimie.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/astrologie.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/chirurgie.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/non-haut-revant.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/haut-revant.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-queues.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-queue.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-souffles.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-tetes.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/hr-signes-draconiques.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/hr-rencontres.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/hr-sorts.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/hr-sorts-reserve.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/hr-meditations.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/hr-casestmr.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/xp-journal.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/editor-notes-mj.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/inventaire.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-item.html', "systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-monnaie.html", 'systems/foundryvtt-reve-de-dragon/templates/actor/liens-animaux.hbs', 'systems/foundryvtt-reve-de-dragon/templates/actor/liens-suivants.hbs', 'systems/foundryvtt-reve-de-dragon/templates/actor/liens-vehicules.hbs', 'systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire-item.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs', //Items 'systems/foundryvtt-reve-de-dragon/templates/scripts/autocomplete-script.hbs', 'systems/foundryvtt-reve-de-dragon/templates/scripts/autocomplete.hbs', 'systems/foundryvtt-reve-de-dragon/templates/item/boutons-comestible.html', 'systems/foundryvtt-reve-de-dragon/templates/item/icon-arme-broken.hbs', 'systems/foundryvtt-reve-de-dragon/templates/item/temporel.hbs', 'systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.html', '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/item-queue-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/header-item.html', // partial enums 'systems/foundryvtt-reve-de-dragon/templates/enum-aspect-tarot.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-base-competence.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-caracteristiques.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-categories.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-ingredient.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-parade.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-potion.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-queue.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-vehicule.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-competence.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-draconic.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-heures.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-initpremierround.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-mortalite.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-niveau-ethylisme.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-periode.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-rarete.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-tmr-effet.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-tmr-type.html', // Partials 'systems/foundryvtt-reve-de-dragon/templates/coeur/chat-effet-tendre-moment.hbs', 'systems/foundryvtt-reve-de-dragon/templates/coeur/afficher-coeur.hbs', 'systems/foundryvtt-reve-de-dragon/templates/tirage/liste-resultats-recherche.hbs', 'systems/foundryvtt-reve-de-dragon/templates/time/horloge.hbs', 'systems/foundryvtt-reve-de-dragon/templates/voyage/fatigue-actor.hbs', 'systems/foundryvtt-reve-de-dragon/templates/voyage/option-vitesse-fatigue.hbs', 'systems/foundryvtt-reve-de-dragon/templates/common/timestamp.hbs', 'systems/foundryvtt-reve-de-dragon/templates/common/date-heure.hbs', 'systems/foundryvtt-reve-de-dragon/templates/common/periodicite.hbs', 'systems/foundryvtt-reve-de-dragon/templates/common/enum-duree.hbs', 'systems/foundryvtt-reve-de-dragon/templates/common/compendium-link.hbs', 'systems/foundryvtt-reve-de-dragon/templates/partial-description-overflow.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-description-sort.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-astrologique.hbs', 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-coeur.hbs', 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-competences.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffLibre.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffFixe.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffCondition.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-enctotal.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-forcer.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-moral.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-surenc.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-select-carac.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-item-hautrevant.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-item-frequence.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-item-description.html', 'systems/foundryvtt-reve-de-dragon/templates/roll/explain.hbs', 'systems/foundryvtt-reve-de-dragon/templates/resolution-table.html', // Dialogs 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-resolution.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-carac.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-sort.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-encaisser.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-validation-encaissement.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-meditation.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-alchimie.html', 'systems/foundryvtt-reve-de-dragon/templates/sommeil/sommeil-actor-moral.hbs', 'systems/foundryvtt-reve-de-dragon/templates/sommeil/astrologie-gardien.hbs', 'systems/foundryvtt-reve-de-dragon/templates/sommeil/astrologie-joueur.hbs', 'systems/foundryvtt-reve-de-dragon/templates/sommeil/astrologie-theme.hbs', // HUD 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.html', 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html', // messages tchat 'systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-description.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-info-appel-au-moral.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-info-distance.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-acteur.hbs', 'systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-sante.hbs', 'systems/foundryvtt-reve-de-dragon/templates/chat-actor-competence-xp.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-actor-carac-xp.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-potionenchantee-chateaudormant.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-fabriquer-potion-base.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html' ]; Handlebars.registerHelper('either', (a, b) => a ?? b); Handlebars.registerHelper('upperFirst', str => Misc.upperFirst(str ?? 'Null')); Handlebars.registerHelper('lowerFirst', str => Misc.lowerFirst(str ?? 'Null')); Handlebars.registerHelper('upper', str => str?.toUpperCase() ?? ''); Handlebars.registerHelper('lowercase', str => str?.toLowerCase() ?? ''); Handlebars.registerHelper('le', str => Grammar.articleDetermine(str)); 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('RDD_CONFIG', path => RDD_CONFIG[path]) Handlebars.registerHelper('computeResolutionScore', (row, col) => RdDResolutionTable.computePercentage(row, col)); Handlebars.registerHelper('computeResolutionChances', (row, col) => RdDResolutionTable.computeChances(row, col)); Handlebars.registerHelper('buildLigneInventaire', (item, options) => { return new Handlebars.SafeString(RdDUtility.buildLigneInventaire(item, options)); }); Handlebars.registerHelper('buildInventaireConteneur', (actorId, itemId, options) => { return new Handlebars.SafeString(RdDUtility.buildInventaireConteneur(actorId, itemId, options)); }); Handlebars.registerHelper('buildContenuConteneur', (item, options) => { return new Handlebars.SafeString(RdDUtility.buildContenuConteneur(item, options)); }); 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)); Handlebars.registerHelper('effetRencontre-name', coord => TMRUtility.typeTmrName(coord)); Handlebars.registerHelper('timestamp-imgSigneHeure', (heure) => { return new Handlebars.SafeString(RdDTimestamp.imgSigneHeure(heure)) }); Handlebars.registerHelper('timestamp-imgSigne', (heure) => { return new Handlebars.SafeString(RdDTimestamp.imgSigne(heure)) }); Handlebars.registerHelper('timestamp-extract', timestamp => new RdDTimestamp(timestamp).toCalendrier()); Handlebars.registerHelper('timestamp-formulesDuree', () => RdDTimestamp.formulesDuree()); Handlebars.registerHelper('timestamp-formulesPeriode', () => RdDTimestamp.formulesPeriode()); Handlebars.registerHelper('array-includes', (array, value) => array.includes(value)); Handlebars.registerHelper('min', (...args) => Math.min(...args.slice(0, -1))); Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionnelles.isUsing(option)); Handlebars.registerHelper('trier', list => list.sort((a, b) => a.name.localeCompare(b.name))); Handlebars.registerHelper('filtreTriCompetences', competences => RdDItemCompetence.triVisible(competences)); Handlebars.registerHelper('linkCompendium', (pack, id, name) => RdDUtility.linkCompendium(pack, id, name)); Handlebars.registerHelper('uniteQuantite', (itemId, actorId) => RdDUtility.getItem(itemId, actorId)?.getUniteQuantite()); Handlebars.registerHelper('isFieldInventaireModifiable', (type, field) => RdDItem.isFieldInventaireModifiable(type, field)); Handlebars.registerHelper('rarete-getChamp', (rarete, field) => RdDRaretes.getChamp(rarete, field)); Handlebars.registerHelper('plusMoins', diff => (diff > 0 ? '+' : '') + Math.round(diff)) Handlebars.registerHelper('experienceLog-topic', topic => ExperienceLog.labelTopic(topic)); // Handle v12 removal of this helper Handlebars.registerHelper('select', function (selected, options) { const escapedValue = RegExp.escape(Handlebars.escapeExpression(selected)); const rgx = new RegExp(' value=[\"\']' + escapedValue + '[\"\']'); const html = options.fn(this); return html.replace(rgx, "$& selected"); }); return loadTemplates(templatePaths); } static getItem(itemId, actorId = undefined) { return actorId ? game.actors.get(actorId)?.getItem(itemId) : game.items.get(itemId); } static linkCompendium(pack, id, name) { return `@Compendium[${pack}.${id}]{${name}}`; } /* -------------------------------------------- */ static buildListOptions(min, max) { let options = "" for (let i = min; i <= max; i++) { options += `` } return options; } /* -------------------------------------------- */ static arrayOrEmpty(items) { if (items?.length) { return items; } return []; } /* -------------------------------------------- */ static getNomEthylisme(niveauEthylisme) { return niveauEthylisme > 0 ? 'Aucun' : nomEthylisme[-niveauEthylisme] } /* -------------------------------------------- */ static toggleAfficheContenu(conteneurId) { RdDUtility.afficheContenu[conteneurId] = !RdDUtility.afficheContenu[conteneurId]; } /* -------------------------------------------- */ static getAfficheContenu(conteneurId) { if (conteneurId) return RdDUtility.afficheContenu[conteneurId]; return undefined; } /* -------------------------------------------- */ static buildArbreDeConteneurs(conteneurs, inventaires) { let objetVersConteneur = {}; // Attribution des objets aux conteneurs for (let conteneur of conteneurs) { if (conteneur.isConteneur()) { conteneur.subItems = []; for (let id of conteneur.system.contenu ?? []) { let objet = inventaires.find(objet => (id == objet._id)); if (objet) { objet.estContenu = true; objetVersConteneur[id] = conteneur._id; conteneur.subItems.push(objet); } } } } for (let conteneur of conteneurs) { conteneur.system.encTotal = RdDUtility.calculEncContenu(conteneur, inventaires); } return objetVersConteneur; } /* -------------------------------------------- */ static calculEncContenu(conteneur, inventaires) { const contenus = (conteneur.system.contenu ?? []).filter(id => id != undefined) .map(id => inventaires.find(it => (id == it.id))) .filter(it => it); let enc = Number(conteneur.system.encombrement ?? 0) * Number(conteneur.system.quantite ?? 1); for (let contenu of contenus) { if (contenu.type == 'conteneur') { enc += RdDUtility.calculEncContenu(contenu, inventaires); } else { enc += Number(contenu.system.encombrement ?? 0) * Number(contenu.system.quantite ?? 1) } } return enc } /* -------------------------------------------- */ // Construit la liste des conteneurs de niveau 1 (c'est à dire non contenu eux-même dans un conteneur) static conteneursRacine(conteneurs) { return conteneurs.filter((conteneur, index, arr) => !conteneur.estContenu); } static prepareOptionsArbreInventaire(item, optionsArbre) { if (!optionsArbre.profondeur) { optionsArbre.profondeur = 1 }; if (!optionsArbre.templateItem) { optionsArbre.templateItem = item.parent?.type == 'commerce' ? "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire-item.html" : "systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-item.html"; } item.niveau = optionsArbre.profondeur; } /* -------------------------------------------- */ /** * Construit la structure récursive des conteneurs, avec imbrication potentielle */ static buildLigneInventaire(item, options = {}, optionsArbre = { ouvert: false, profondeur: 1 }) { RdDUtility.prepareOptionsArbreInventaire(item, optionsArbre); const isConteneur = item.type == 'conteneur'; const inventaire = { item: item, vide: isConteneur && item.system.contenu.length == 0, ouvert: isConteneur && RdDUtility.getAfficheContenu(item._id), options: options }; optionsArbre.ouvert = inventaire.ouvert const ligneObjet = Handlebars.partials[optionsArbre.templateItem](inventaire); if (isConteneur) { return ligneObjet + RdDUtility.buildContenuConteneur(item, options, optionsArbre); } return ligneObjet; } static buildInventaireConteneur(actorId, itemId, options) { const actor = game.actors.get(actorId) const item = actor?.items.get(itemId) if (item) { return RdDUtility.buildContenuConteneur(item, options, { ouvert: true, profondeur: 1 }); } return ''; } /* -------------------------------------------- */ static buildContenuConteneur(conteneur, options = {}, optionsArbre = {}) { RdDUtility.prepareOptionsArbreInventaire(conteneur, optionsArbre); const display = optionsArbre.ouvert ? 'item-display-show' : 'item-display-hide'; const profondeur = optionsArbre.profondeur; optionsArbre.profondeur++; const lignesContenu = conteneur.subItems.sort(Misc.ascending(it => it.name)) .map(contenu => this.buildLigneInventaire(contenu, options, optionsArbre)); return `
Etes vous certain de vouloir supprimer le lien vers ${subActor.name} ?
`, title: 'Confirmer la suppression', buttonLabel: 'Supprimer le lien', onAction: onSuppression }) } /* -------------------------------------------- */ static async confirmActorItemDelete(sheet, item, htmlToDelete) { const itemId = item.id; const confirmationSuppression = { settingConfirmer: "confirmation-supprimer-" + item.getItemGroup(), content: `Etes vous certain de vouloir supprimer: ${item.name}?
`, title: `Supprimer ${item.name}`, buttonLabel: "Supprimer", onAction: () => { console.log('Delete : ', itemId); sheet.actor.deleteEmbeddedDocuments('Item', [itemId], { renderSheet: false }); RdDUtility.slideOnDelete(sheet, htmlToDelete); } }; if (item.isConteneurNonVide()) { confirmationSuppression.content += `Ce conteneur n'est pas vide. Que voulez vous supprimer?
`; confirmationSuppression.settingConfirmer = undefined; RdDConfirm.confirmer(confirmationSuppression, { 'deleteall': { icon: '', label: "Supprimer conteneur et contenu", callback: () => { console.log("Delete : ", itemId); sheet.actor.deleteAllConteneur(itemId, { renderSheet: false }); RdDUtility.slideOnDelete(sheet, htmlToDelete); } } }); } else { RdDConfirm.confirmer(confirmationSuppression) } } static slideOnDelete(sheet, htmlToDelete) { return htmlToDelete?.slideUp(200, () => sheet.render(false)); } /* -------------------------------------------- */ static afficherHeuresChanceMalchance(heureNaissance) { if (game.user.isGM) { const heure = RdDTimestamp.findHeure(heureNaissance - 1); if (heureNaissance && heure) { let ajustement = game.system.rdd.calendrier.getAjustementAstrologique(heureNaissance); const current = game.system.rdd.calendrier.heureCourante(); ChatMessage.create({ content: `A l'heure de ${current.label}, le modificateur de Chance/Malchance est de ${Misc.toSignedString(ajustement)} pour l'heure de naissance ${heure.label}.`, whisper: ChatMessage.getWhisperRecipients("GM") }); } else if (heureNaissance) { ui.notifications.warn(heureNaissance + " ne correspond pas à une heure de naissance"); } else { ui.notifications.warn("Pas d'heure de naissance selectionnée"); } } else { ui.notifications.warn("Vous n'avez pas accès à cette commande"); } } /*-------------------------------------------- */ static checkThanatosXP(compName) { if (compName.includes('Thanatos')) { let message = "Vous avez mis des points d'Expérience dans la Voie de Thanatos !