forked from public/foundryvtt-reve-de-dragon
		
	Export csv pour Scriptarium
Activable dans les options avancées du système Un menu contextuel permet d'écrire dans les logs
This commit is contained in:
		
							
								
								
									
										73
									
								
								module/actor/export-scriptarium/export-scriptarium.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								module/actor/export-scriptarium/export-scriptarium.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | |||||||
|  | import { LOG_HEAD } from "../../constants.js" | ||||||
|  | import { ACTOR_TYPES } from "../../item.js" | ||||||
|  | import { Misc } from "../../misc.js" | ||||||
|  | import { EXPORT_CSV_SCRIPTARIUM, OptionsAvancees } from "../../settings/options-avancees.js" | ||||||
|  | import { Mapping } from "./mapping.js" | ||||||
|  |  | ||||||
|  | const IMG_SCRIPTARIUM = '<img class="context-menu-img" src="systems/foundryvtt-reve-de-dragon/styles/img/ui/scriptarium.svg">' | ||||||
|  |  | ||||||
|  | export class ExportScriptarium { | ||||||
|  |  | ||||||
|  |   static init() { | ||||||
|  |     ExportScriptarium.INSTANCE = new ExportScriptarium() | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   constructor() { | ||||||
|  |     this.mapping = Mapping.getMapping() | ||||||
|  |     Hooks.on("getActorDirectoryFolderContext", (actorDirectory, menus) => { ExportScriptarium.INSTANCE.onActorDirectoryMenu(actorDirectory, menus) }) | ||||||
|  |     Hooks.on("getActorDirectoryEntryContext", (actorDirectory, menus) => { ExportScriptarium.INSTANCE.onActorDirectoryMenu(actorDirectory, menus) }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   onActorDirectoryMenu(actorDirectory, menus) { | ||||||
|  |     menus.push({ | ||||||
|  |       name: 'Export Personnages', | ||||||
|  |       icon: IMG_SCRIPTARIUM, | ||||||
|  |       condition: (target) => game.user.isGM && | ||||||
|  |         OptionsAvancees.isUsing(EXPORT_CSV_SCRIPTARIUM) && | ||||||
|  |         this.$getActors(actorDirectory, target).length > 0, | ||||||
|  |       callback: target => this.exportActors(this.$getActors(actorDirectory, target)) | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   $getActors(actorDirectory, target) { | ||||||
|  |     const li = target.closest(".directory-item") | ||||||
|  |     const folderId = li.data("folderId") | ||||||
|  |     const actorId = li.data("documentId") | ||||||
|  |     const actors = actorId | ||||||
|  |       ? [game.actors.get(actorId)] | ||||||
|  |       : folderId | ||||||
|  |         ? actorDirectory.folders.find(it => it.id == folderId).contents | ||||||
|  |         : [] | ||||||
|  |     return actors.filter(it => it.type == ACTOR_TYPES.personnage) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   exportActors(actors) { | ||||||
|  |     console.log(LOG_HEAD + 'exportActors', actors) | ||||||
|  |     const header = Misc.join(this.getHeaderLine(), ';') | ||||||
|  |     console.log(header) | ||||||
|  |     actors.forEach(actor => { | ||||||
|  |       const actorLine = Misc.join(this.getActorLine(actor), ';') | ||||||
|  |       console.log(actorLine) | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   getHeaderLine() { | ||||||
|  |     return this.mapping.map(it => it.column) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   getActorLine(actor) { | ||||||
|  |     const context = Mapping.prepareContext(actor) | ||||||
|  |     return this.mapping.map(it => it.getter(actor, context)) | ||||||
|  |       .map(it => this.$escapeQuotes(it)) | ||||||
|  |       .map(it => it.replaceAll("\n", " ").replaceAll("\r", "")) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   $escapeQuotes(it) { | ||||||
|  |     it = '' + it | ||||||
|  |     if (it.includes('"') || it.includes(';')) { | ||||||
|  |       return `"${it.replaceAll('"', '\\"')}"` | ||||||
|  |     } | ||||||
|  |     return it | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										303
									
								
								module/actor/export-scriptarium/mapping.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										303
									
								
								module/actor/export-scriptarium/mapping.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,303 @@ | |||||||
|  | import { Grammar } from "../../grammar.js" | ||||||
|  | import { RdDItemArme } from "../../item-arme.js" | ||||||
|  | import { RdDItemCompetence } from "../../item-competence.js" | ||||||
|  | import { RdDItemSort } from "../../item-sort.js" | ||||||
|  | import { ITEM_TYPES } from "../../item.js" | ||||||
|  | import { Misc } from "../../misc.js" | ||||||
|  | import { RdDTimestamp } from "../../time/rdd-timestamp.js" | ||||||
|  | import { TMRConstants } from "../../tmr-constants.js" | ||||||
|  | import { TMRUtility } from "../../tmr-utility.js" | ||||||
|  |  | ||||||
|  | const CATEGORIES_COMPETENCES = [ | ||||||
|  |   "generale", | ||||||
|  |   "particuliere", | ||||||
|  |   "specialisee", | ||||||
|  |   "connaissance", | ||||||
|  | ] | ||||||
|  | const CATEGORIES_DRACONIC = [ | ||||||
|  |   "draconic", | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | const CATEGORIES_COMBAT = [ | ||||||
|  |   "melee", | ||||||
|  |   "tir", | ||||||
|  |   "lancer" | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | const NIVEAU_BASE = { | ||||||
|  |   "generale": -4, | ||||||
|  |   "particuliere": -8, | ||||||
|  |   "specialisee": -11, | ||||||
|  |   "connaissance": -11, | ||||||
|  |   "draconic": -11, | ||||||
|  |   "melee": -6, | ||||||
|  |   "tir": -8, | ||||||
|  |   "lancer": -8, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class ColumnMappingFactory { | ||||||
|  |   static createMappingArme(part, i) { | ||||||
|  |     return { column: `arme-${part}-${i}`, getter: (actor, context) => Mapping.getArme(actor, context, part, i) } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static createMappingSort(part, i) { | ||||||
|  |     return { column: `sort-${part}-${i}`, getter: (actor, context) => Mapping.getSort(actor, context, part, i) } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const NB_ARMES = 10 | ||||||
|  | const NB_SORTS = 20 | ||||||
|  | const TABLEAU_ARMES = [...Array(NB_ARMES).keys()] | ||||||
|  | const TABLEAU_SORTS = [...Array(NB_SORTS).keys()] | ||||||
|  |  | ||||||
|  | const MAPPING_BASE = [ | ||||||
|  |   { column: "ID", getter: (actor, context) => actor.id }, | ||||||
|  |   { column: "name", getter: (actor, context) => actor.name }, | ||||||
|  |   //    { column: "biographie", getter: (actor, context) => actor.system.biographie }, | ||||||
|  |   { column: "taille", getter: (actor, context) => actor.system.carac.taille.value }, | ||||||
|  |   { column: "apparence", getter: (actor, context) => actor.system.carac.apparence.value }, | ||||||
|  |   { column: "constitution", getter: (actor, context) => actor.system.carac.constitution.value }, | ||||||
|  |   { column: "force", getter: (actor, context) => actor.system.carac.force.value }, | ||||||
|  |   { column: "agilite", getter: (actor, context) => actor.system.carac.agilite.value }, | ||||||
|  |   { column: "dexterite", getter: (actor, context) => actor.system.carac.dexterite.value }, | ||||||
|  |   { column: "vue", getter: (actor, context) => actor.system.carac.vue.value }, | ||||||
|  |   { column: "ouie", getter: (actor, context) => actor.system.carac.ouie.value }, | ||||||
|  |   { column: "odoratgout", getter: (actor, context) => actor.system.carac.odoratgout.value }, | ||||||
|  |   { column: "volonte", getter: (actor, context) => actor.system.carac.volonte.value }, | ||||||
|  |   { column: "intellect", getter: (actor, context) => actor.system.carac.intellect.value }, | ||||||
|  |   { column: "empathie", getter: (actor, context) => actor.system.carac.empathie.value }, | ||||||
|  |   { column: "reve", getter: (actor, context) => actor.system.carac.reve.value }, | ||||||
|  |   { column: "chance", getter: (actor, context) => actor.system.carac.chance.value }, | ||||||
|  |   { column: "melee", getter: (actor, context) => actor.system.carac.melee.value }, | ||||||
|  |   { column: "tir", getter: (actor, context) => actor.system.carac.tir.value }, | ||||||
|  |   { column: "lancer", getter: (actor, context) => actor.system.carac.lancer.value }, | ||||||
|  |   { column: "derobee", getter: (actor, context) => actor.system.carac.derobee.value }, | ||||||
|  |   { column: "vie", getter: (actor, context) => actor.system.sante.vie.max }, | ||||||
|  |   { column: "plusdom", getter: (actor, context) => actor.system.attributs.plusdom.value }, | ||||||
|  |   { column: "protectionnaturelle", getter: (actor, context) => actor.system.attributs.protection.value }, | ||||||
|  |   { column: "endurance", getter: (actor, context) => actor.system.sante.endurance.max }, | ||||||
|  |   { column: "description", getter: (actor, context) => Mapping.getDescription(actor) }, | ||||||
|  |   { column: "armure", getter: (actor, context) => Mapping.getArmure(actor, context) }, | ||||||
|  |   { column: "protection", getter: (actor, context) => Mapping.getProtectionArmure(actor, context) }, | ||||||
|  |   { column: "malus-armure", getter: (actor, context) => Mapping.getMalusArmure(actor, context) }, | ||||||
|  |   { column: "esquive", getter: (actor, context) => Mapping.getEsquive(actor, context) }, | ||||||
|  |   { column: "esquive-niv", getter: (actor, context) => Mapping.getEsquiveNiveau(context) }, | ||||||
|  |   { column: "competences", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_COMPETENCES) }, | ||||||
|  |   { column: "draconic", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_DRACONIC) }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | const MAPPING_ARMES = TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('name', i)) | ||||||
|  |   .concat(TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('niveau', i))) | ||||||
|  |   .concat(TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('init', i))) | ||||||
|  |   .concat(TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('dom', i))) | ||||||
|  | const MAPPING_SORTS = TABLEAU_SORTS.map(i => ColumnMappingFactory.createMappingSort('voie', i)) | ||||||
|  |   .concat(TABLEAU_SORTS.map(i => ColumnMappingFactory.createMappingSort('description', i))) | ||||||
|  |   .concat(TABLEAU_SORTS.map(i => ColumnMappingFactory.createMappingSort('bonus', i))) | ||||||
|  | const MAPPING = MAPPING_BASE | ||||||
|  |   .concat(MAPPING_ARMES) | ||||||
|  |   .concat(MAPPING_SORTS) | ||||||
|  |  | ||||||
|  | export class Mapping { | ||||||
|  |  | ||||||
|  |   static getMapping() { | ||||||
|  |     return MAPPING | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static prepareContext(actor) { | ||||||
|  |     return { | ||||||
|  |       armes: Mapping.prepareArmes(actor), | ||||||
|  |       armure: Mapping.prepareArmure(actor), | ||||||
|  |       esquive: Mapping.prepareEsquive(actor), | ||||||
|  |       sorts: Mapping.prepareSorts(actor) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static prepareArmes(actor) { | ||||||
|  |     return actor.items.filter(it => it.type == ITEM_TYPES.arme) | ||||||
|  |       .map(arme => { | ||||||
|  |         const compToUse = RdDItemArme.getCompetenceArme(arme, 'competence'); | ||||||
|  |         const comp = actor.getCompetence(compToUse); | ||||||
|  |         const bonusDom = Mapping.calculBonusDom(comp, actor) | ||||||
|  |         return { | ||||||
|  |           name: arme.name, | ||||||
|  |           niveau: comp.system.niveau, | ||||||
|  |           init: Mapping.calculBaseInit(actor, comp.system.categorie) + comp.system.niveau, | ||||||
|  |           dom: Number(arme.system.dommages) + bonusDom | ||||||
|  |         }; | ||||||
|  |       }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static calculBonusDom(comp, actor) { | ||||||
|  |     // TODO: reuse dmg calc? | ||||||
|  |     const appliesBonusDom = ['melee', 'lancer'].includes(comp.system.categorie) | ||||||
|  |     return appliesBonusDom ? Number(actor.system.attributs.plusdom.value) : 0 | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static calculBaseInit(actor, categorie) { | ||||||
|  |     // TODO: reuse init calc? | ||||||
|  |     const mapping = MAPPING_BASE.find(it => it.column == categorie) | ||||||
|  |     if (mapping) { | ||||||
|  |       switch (categorie) { | ||||||
|  |         case 'melee': | ||||||
|  |         case 'tir': | ||||||
|  |         case 'lancer': | ||||||
|  |           const caracteristique = Number(actor.system.carac[categorie].value) | ||||||
|  |           return Math.floor(caracteristique / 2) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return 0 | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static prepareArmure(actor) { | ||||||
|  |     const armures = actor.itemTypes[ITEM_TYPES.armure].filter(it => it.system.equipe) | ||||||
|  |     if (armures.length > 1) { | ||||||
|  |       console.warn(`${actor.name} a équipé ${armures.length} armures, seule la première sera considérée`) | ||||||
|  |     } | ||||||
|  |     if (armures.length > 0) { | ||||||
|  |       const armure = armures[0] | ||||||
|  |       return { | ||||||
|  |         name: armure.name, | ||||||
|  |         protection: armure.system.protection, | ||||||
|  |         malus: armure.system.malus ?? 0 | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return { | ||||||
|  |       name: '', | ||||||
|  |       protection: actor.system.attributs.protection.value, | ||||||
|  |       malus: 0 | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static prepareEsquive(actor) { | ||||||
|  |     const esquives = actor.getCompetences("Esquive") | ||||||
|  |     if (esquives.length > 0) { | ||||||
|  |       const esquive = esquives[0] | ||||||
|  |       return { | ||||||
|  |         name: esquive.name, | ||||||
|  |         niveau: esquive.system.niveau | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return undefined | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static prepareSorts(actor) { | ||||||
|  |     return actor.itemTypes[ITEM_TYPES.sort].map(it => { | ||||||
|  |       return { | ||||||
|  |         voie: it.system.voie, | ||||||
|  |         description: Mapping.descriptionSort(it), | ||||||
|  |         bonus: Mapping.bonusCase(it) | ||||||
|  |       } | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static descriptionSort(sort) { | ||||||
|  |     const ptSeuil = Array(sort.system.coutseuil).map(it => '*') | ||||||
|  |     const caseTMR = sort.system.caseTMRspeciale.length > 0 ? sort.system.caseTMRspeciale : sort.system.caseTMR | ||||||
|  |     return `${sort.name}${ptSeuil} (${caseTMR}) R${sort.system.difficulte} r${sort.system.ptreve}` | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static bonusCase(sort) { | ||||||
|  |     const list = RdDItemSort.buildBonusCaseList(sort.system.bonuscase, false).sort(Misc.descending(it => it.bonus)) | ||||||
|  |     if (list.length > 0) { | ||||||
|  |       const bonus = list[0] | ||||||
|  |       return `+${bonus.bonus}% en ${bonus.case}` | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static getDescription(actor) { | ||||||
|  |     const sexe = actor.system.sexe | ||||||
|  |     const sexeFeminin = sexe.length > 0 && sexe.charAt(0).toLowerCase() == 'f' ? 'Née' : 'Né' | ||||||
|  |     const race = ['', 'humain'].includes(Grammar.toLowerCaseNoAccent(actor.system.race)) ? '' : (actor.system.race + ' ') | ||||||
|  |     const heure = actor.system.heure | ||||||
|  |     const hn = `${sexeFeminin} à l'heure ${RdDTimestamp.definition(heure).avecArticle}` | ||||||
|  |     const age = actor.system.age ? `${actor.system.age} ans` : undefined | ||||||
|  |     const taille = actor.system.taille | ||||||
|  |     const poids = actor.system.poids | ||||||
|  |     const cheveux = actor.system.cheveux ? `cheveux ${actor.system.cheveux}` : undefined | ||||||
|  |     const yeux = actor.system.yeux ? `yeux ${actor.system.yeux}` : undefined | ||||||
|  |     const beaute = actor.system.beaute ? `Beauté ${actor.system.beaute}` : undefined | ||||||
|  |     const list = [race, hn, age, taille, poids, cheveux, yeux, beaute] | ||||||
|  |     return Misc.join(list.filter(it => it), ', ') | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static getArmure(actor, context) { | ||||||
|  |     return context.armure?.name ?? '' | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static getProtectionArmure(actor, context) { | ||||||
|  |     return Number(context?.armure?.protection ?? 0) + Number(actor.system.attributs.protection.value) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static getMalusArmure(actor, context) { | ||||||
|  |     return context?.armure?.malus ?? 0 | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static getEsquive(actor, context) { | ||||||
|  |     return context.esquive?.name ?? '' | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static getEsquiveNiveau(context) { | ||||||
|  |     if (context.esquive) { | ||||||
|  |       const niveau = context.esquive.niveau + context.armure.malus | ||||||
|  |       return niveau > 0 ? ('+' + niveau) : ('' + niveau) | ||||||
|  |     } | ||||||
|  |     return '' | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static getCompetences(actor, categories) { | ||||||
|  |     const competences = Mapping.getCompetencesCategorie(actor, categories) | ||||||
|  |     if (competences.length == 0) { | ||||||
|  |       return '' | ||||||
|  |     } | ||||||
|  |     const byCartegories = Mapping.competencesByCategoriesByNiveau(competences, categories) | ||||||
|  |     const txtByCategories = Object.values(byCartegories) | ||||||
|  |       .map(it => it.competencesParNiveau) | ||||||
|  |       .map(byNiveau => { | ||||||
|  |         const niveaux = Object.keys(byNiveau).map(it => Number(it)).sort(Misc.ascending()) | ||||||
|  |         if (niveaux.length == 0) { | ||||||
|  |           return '' | ||||||
|  |         } | ||||||
|  |         const txtCategorieByNiveau = niveaux.map(niveau => { | ||||||
|  |           const names = Misc.join(byNiveau[niveau].map(it => it.name).sort(Misc.ascending()), ', ') | ||||||
|  |           return names + ': ' + Misc.toSignedString(niveau) | ||||||
|  |         } | ||||||
|  |         ) | ||||||
|  |         const txtCategorie = Misc.join(txtCategorieByNiveau, ' / ') | ||||||
|  |         return txtCategorie | ||||||
|  |       }).filter(it => it != '') | ||||||
|  |  | ||||||
|  |     return Misc.join(txtByCategories, ' / ') | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static competencesByCategoriesByNiveau(competences, categories) { | ||||||
|  |     return categories.map(c => { | ||||||
|  |       return { | ||||||
|  |         categorie: c, | ||||||
|  |         competencesParNiveau: Misc.classify( | ||||||
|  |           competences.filter(comp => comp.system.categorie == c), | ||||||
|  |           comp => comp.system.niveau) | ||||||
|  |       } | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static getArme(actor, context, part, numero) { | ||||||
|  |     if (numero < context.armes.length) { | ||||||
|  |       return context.armes[numero][part] ?? '' | ||||||
|  |     } | ||||||
|  |     return '' | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static getCompetencesCategorie(actor, categories) { | ||||||
|  |     return actor.itemTypes[ITEM_TYPES.competence] | ||||||
|  |       .filter(it => categories.includes(it.system.categorie)) | ||||||
|  |       .filter(it => !RdDItemCompetence.isNiveauBase(it)) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static getSort(actor, context, part, numero) { | ||||||
|  |     if (numero < context.sorts.length) { | ||||||
|  |       return context.sorts[numero][part] | ||||||
|  |     } | ||||||
|  |     return '' | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| @@ -65,6 +65,8 @@ import { AutoAdjustDarkness as AutoAdjustDarkness } from "./time/auto-adjust-dar | |||||||
| import { RdDCreature } from "./actor/creature.js" | import { RdDCreature } from "./actor/creature.js" | ||||||
| import { RdDTMRDialog } from "./rdd-tmr-dialog.js" | import { RdDTMRDialog } from "./rdd-tmr-dialog.js" | ||||||
| import { RdDActorExportSheet } from "./actor/actor-export-sheet.js" | import { RdDActorExportSheet } from "./actor/actor-export-sheet.js" | ||||||
|  | import { OptionsAvancees } from "./settings/options-avancees.js" | ||||||
|  | import { ExportScriptarium } from "./actor/export-scriptarium/export-scriptarium.js" | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * RdD system |  * RdD system | ||||||
| @@ -197,6 +199,7 @@ export class SystemReveDeDragon { | |||||||
|     SystemCompendiums.init() |     SystemCompendiums.init() | ||||||
|     DialogChronologie.init() |     DialogChronologie.init() | ||||||
|     ReglesOptionnelles.init() |     ReglesOptionnelles.init() | ||||||
|  |     OptionsAvancees.init() | ||||||
|     RdDUtility.init() |     RdDUtility.init() | ||||||
|     RdDDice.init() |     RdDDice.init() | ||||||
|     RdDCommands.init() |     RdDCommands.init() | ||||||
| @@ -211,6 +214,7 @@ export class SystemReveDeDragon { | |||||||
|     RdDPossession.init() |     RdDPossession.init() | ||||||
|     TMRRencontres.init() |     TMRRencontres.init() | ||||||
|     Environnement.init() |     Environnement.init() | ||||||
|  |     ExportScriptarium.init() | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   initSystemSettings() { |   initSystemSettings() { | ||||||
|   | |||||||
							
								
								
									
										91
									
								
								module/settings/options-avancees.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								module/settings/options-avancees.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | |||||||
|  | import { SYSTEM_RDD } from "../constants.js" | ||||||
|  | import { Misc } from "../misc.js" | ||||||
|  |  | ||||||
|  | export const EXPORT_CSV_SCRIPTARIUM = 'export-csv-scriptarium' | ||||||
|  |  | ||||||
|  | const OPTIONS_AVANCEES = [ | ||||||
|  |   { group: 'Menus', name: EXPORT_CSV_SCRIPTARIUM, descr: "Proposer le menu d'export csv Scriptarium (raffraichissement requis)" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | export class OptionsAvancees extends FormApplication { | ||||||
|  |   static init() { | ||||||
|  |     for (const regle of OPTIONS_AVANCEES) { | ||||||
|  |       const name = regle.name | ||||||
|  |       const id = OptionsAvancees._getId(name) | ||||||
|  |       game.settings.register(SYSTEM_RDD, id, { name: id, scope: regle.scope ?? "world", config: false, default: regle.default == undefined ? true : regle.default, type: Boolean }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     game.settings.registerMenu(SYSTEM_RDD, "rdd-options-avancees", { | ||||||
|  |       name: "Configurer les options avancées", | ||||||
|  |       label: "Options avancées", | ||||||
|  |       hint: "Ouvre la fenêtre de configuration des options avancées", | ||||||
|  |       icon: "fas fa-bars", | ||||||
|  |       type: OptionsAvancees | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   constructor(...args) { | ||||||
|  |     super(...args) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static _getId(name) { | ||||||
|  |     return `rdd-advanced-${name}` | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static get defaultOptions() { | ||||||
|  |     return foundry.utils.mergeObject(super.defaultOptions, { | ||||||
|  |       id: "options-avancees", | ||||||
|  |       template: "systems/foundryvtt-reve-de-dragon/templates/settings/options-avancees.hbs", | ||||||
|  |       height: 650, | ||||||
|  |       width: 550, | ||||||
|  |       minimizable: false, | ||||||
|  |       closeOnSubmit: true, | ||||||
|  |       title: "Options avancées" | ||||||
|  |     }, { inplace: false }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   getData() { | ||||||
|  |     let formData = super.getData() | ||||||
|  |     const regles = OPTIONS_AVANCEES.filter(it => game.user.isGM || it.scope == "client") | ||||||
|  |       .map(it => { | ||||||
|  |         it = foundry.utils.duplicate(it) | ||||||
|  |         it.id = OptionsAvancees._getId(it.name) | ||||||
|  |         it.active = OptionsAvancees.isSet(it.name) | ||||||
|  |         return it | ||||||
|  |       }) | ||||||
|  |     formData.regles = regles | ||||||
|  |     formData.groups = Misc.classify(regles, it => it.group) | ||||||
|  |     return formData | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static getSettingKey(name){ | ||||||
|  |     return `${SYSTEM_RDD}.${this._getId(name)}` | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static isUsing(name) { | ||||||
|  |     return OptionsAvancees.isSet(name) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static isSet(name) { | ||||||
|  |     return game.settings.get(SYSTEM_RDD, OptionsAvancees._getId(name)) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static set(name, value) { | ||||||
|  |     return game.settings.set(SYSTEM_RDD, OptionsAvancees._getId(name), value ? true : false) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   activateListeners(html) { | ||||||
|  |     html.find(".select-option").click((event) => { | ||||||
|  |       if (event.currentTarget.attributes.name) { | ||||||
|  |         let id = event.currentTarget.attributes.name.value | ||||||
|  |         let isChecked = event.currentTarget.checked | ||||||
|  |         game.settings.set(SYSTEM_RDD, id, isChecked) | ||||||
|  |       } | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   async _updateObject(event, formData) { | ||||||
|  |     this.close() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| @@ -15,18 +15,18 @@ export const RDD_MINUTES_PAR_JOUR = 1440; //RDD_HEURES_PAR_JOUR * RDD_MINUTES_PA | |||||||
| const ROUNDS_PAR_MINUTE = 10; | const ROUNDS_PAR_MINUTE = 10; | ||||||
|  |  | ||||||
| const DEFINITION_HEURES = [ | const DEFINITION_HEURES = [ | ||||||
|   { key: "vaisseau", label: "Vaisseau", lettreFont: 'v', saison: "Printemps", darkness: 0.9 }, |   { key: "vaisseau", article: "du ", label: "Vaisseau", lettreFont: 'v', saison: "Printemps", darkness: 0.9 }, | ||||||
|   { key: "sirene", label: "Sirène", lettreFont: 'i', saison: "Printemps", darkness: 0.1 }, |   { key: "sirene", article: "de la ", label: "Sirène", lettreFont: 'i', saison: "Printemps", darkness: 0.1 }, | ||||||
|   { key: "faucon", label: "Faucon", lettreFont: 'f', saison: "Printemps", darkness: 0 }, |   { key: "faucon", article: "du ", label: "Faucon", lettreFont: 'f', saison: "Printemps", darkness: 0 }, | ||||||
|   { key: "couronne", label: "Couronne", lettreFont: '', saison: "Eté", darkness: 0 }, |   { key: "couronne", article: "de la ", label: "Couronne", lettreFont: '', saison: "Eté", darkness: 0 }, | ||||||
|   { key: "dragon", label: "Dragon", lettreFont: 'd', saison: "Eté", darkness: 0 }, |   { key: "dragon", article: "du ", label: "Dragon", lettreFont: 'd', saison: "Eté", darkness: 0 }, | ||||||
|   { key: "epees", label: "Epées", lettreFont: 'e', saison: "Eté", darkness: 0 }, |   { key: "epees", article: "des ", label: "Epées", lettreFont: 'e', saison: "Eté", darkness: 0 }, | ||||||
|   { key: "lyre", label: "Lyre", lettreFont: 'l', saison: "Automne", darkness: 0.1 }, |   { key: "lyre", article: "de la ", label: "Lyre", lettreFont: 'l', saison: "Automne", darkness: 0.1 }, | ||||||
|   { key: "serpent", label: "Serpent", lettreFont: 's', saison: "Automne", darkness: 0.9 }, |   { key: "serpent", article: "du ", label: "Serpent", lettreFont: 's', saison: "Automne", darkness: 0.9 }, | ||||||
|   { key: "poissonacrobate", label: "Poisson Acrobate", lettreFont: 'p', saison: "Automne", darkness: 1 }, |   { key: "poissonacrobate", article: "du ", label: "Poisson Acrobate", lettreFont: 'p', saison: "Automne", darkness: 1 }, | ||||||
|   { key: "araignee", label: "Araignée", lettreFont: 'a', saison: "Hiver", darkness: 1 }, |   { key: "araignee", article: "de l'", label: "Araignée", lettreFont: 'a', saison: "Hiver", darkness: 1 }, | ||||||
|   { key: "roseau", label: "Roseau", lettreFont: 'r', saison: "Hiver", darkness: 1 }, |   { key: "roseau", article: "du ", label: "Roseau", lettreFont: 'r', saison: "Hiver", darkness: 1 }, | ||||||
|   { key: "chateaudormant", label: "Château Dormant", lettreFont: 'c', saison: "Hiver", darkness: 1 }, |   { key: "chateaudormant", article: "du ", label: "Château Dormant", lettreFont: 'c', saison: "Hiver", darkness: 1 }, | ||||||
| ] | ] | ||||||
|  |  | ||||||
| const FORMULES_DUREE = [ | const FORMULES_DUREE = [ | ||||||
| @@ -64,6 +64,7 @@ export class RdDTimestamp { | |||||||
|       DEFINITION_HEURES[i].hh = RdDTimestamp.hh(i); |       DEFINITION_HEURES[i].hh = RdDTimestamp.hh(i); | ||||||
|       DEFINITION_HEURES[i].icon = RdDTimestamp.iconeHeure(i); |       DEFINITION_HEURES[i].icon = RdDTimestamp.iconeHeure(i); | ||||||
|       DEFINITION_HEURES[i].webp = DEFINITION_HEURES[i].icon.replace(".svg", ".webp"); |       DEFINITION_HEURES[i].webp = DEFINITION_HEURES[i].icon.replace(".svg", ".webp"); | ||||||
|  |       DEFINITION_HEURES[i].avecArticle = DEFINITION_HEURES[i].article + DEFINITION_HEURES[i].label | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										65
									
								
								styles/img/ui/scriptarium.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								styles/img/ui/scriptarium.svg
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| After Width: | Height: | Size: 56 KiB | 
| @@ -572,6 +572,15 @@ input:is(.blessure-premiers_soins, .blessure-soins_complets) { | |||||||
|   border: none; |   border: none; | ||||||
|   padding: 0.1rem; |   padding: 0.1rem; | ||||||
| } | } | ||||||
|  | .context-menu-img { | ||||||
|  |   max-width: 2rem; | ||||||
|  |   max-height: 1rem; | ||||||
|  |   flex-grow: 0; | ||||||
|  |   margin: 0.2rem 0.3rem 0 0; | ||||||
|  |   vertical-align: middle; | ||||||
|  |   border: none; | ||||||
|  |   padding: 0rem; | ||||||
|  | } | ||||||
|  |  | ||||||
| .button-img { | .button-img { | ||||||
|   vertical-align: baseline; |   vertical-align: baseline; | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								templates/settings/options-avancees.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								templates/settings/options-avancees.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | <form autocomplete="off" onsubmit="event.preventDefault();"> | ||||||
|  |   {{#each groups as |group key|}} | ||||||
|  |   <h3>{{key}}</h3> | ||||||
|  |   <ul> | ||||||
|  |     {{#each group as |regle r|}} | ||||||
|  |     <li> | ||||||
|  |       <input class="select-option" type="checkbox" name="{{regle.id}}" {{#if regle.active}}checked{{/if}}/> | ||||||
|  |       <label>{{regle.descr}}</label> | ||||||
|  |     </li> | ||||||
|  |     {{/each}} | ||||||
|  |   </ul> | ||||||
|  |   {{/each}} | ||||||
|  | </form> | ||||||
		Reference in New Issue
	
	Block a user