diff --git a/changelog.md b/changelog.md index 8f0d9bc4..20967d6b 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,7 @@ # 12.0 ## 12.0.12 - L'étalage d'Astrobazzarh -- On peut de nouveau vendre des items sans propriétaire, depuis les compendiums ou depuis l'onglet des Objets +- Fix: On peut de nouveau vendre des items sans propriétaire, depuis les compendiums ou depuis l'onglet des Objets +- Début de Feuille PNJ au format des encarts Scriptarium ## 12.0.11 - Le scriptorium d'Astrobazzarh - ajout d'un bouton pour générer les éléments de description d'un personnage diff --git a/module/actor/export-scriptarium/actor-export-sheet.js b/module/actor/export-scriptarium/actor-export-sheet.js new file mode 100644 index 00000000..bfe4a8c3 --- /dev/null +++ b/module/actor/export-scriptarium/actor-export-sheet.js @@ -0,0 +1,49 @@ +import { RdDActorSheet } from "../../actor-sheet.js" +import { SYSTEM_RDD } from "../../constants.js"; +import { Misc } from "../../misc.js"; +import { ExportScriptarium } from "./export-scriptarium.js"; +import { Mapping } from "./mapping.js"; + +export class RdDActorExportSheet extends RdDActorSheet { + static async init() { + await loadTemplates([ + "systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/arme.hbs", + "systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs", + "systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-derivee.hbs", + "systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/esquive.hbs", + "systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/protection.hbs", + "systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs", + ]) + Actors.registerSheet(SYSTEM_RDD, RdDActorExportSheet, { types: ["personnage"], makeDefault: false, label: "Feuille d'encart" }) + } + static get defaultOptions() { + return foundry.utils.mergeObject(RdDActorSheet.defaultOptions, { + template: "systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/actor-export-sheet.hbs", + width: 550, + showCompNiveauBase: false, + vueArchetype: false, + }, { inplace: false }) + } + + constructor(actor, options) { + super(actor, options) + } + + async getData() { + const formData = await super.getData() + const values = Mapping.getAsObject(this.actor); + // Add any structured, precomputed list of data + formData.export = values + return formData + } + + activateListeners(html) { + super.activateListeners(html); + this.html.find('.button-export').click(async event => { + + ExportScriptarium.INSTANCE.exportActors([this.actor], + `${this.actor.uuid}-${this.actor.name}` + ) + }) + } +} diff --git a/module/actor/export-scriptarium/export-scriptarium.js b/module/actor/export-scriptarium/export-scriptarium.js index 42710c70..aea110e7 100644 --- a/module/actor/export-scriptarium/export-scriptarium.js +++ b/module/actor/export-scriptarium/export-scriptarium.js @@ -12,14 +12,13 @@ export class 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', + name: 'Export Personnages ', icon: IMG_SCRIPTARIUM, condition: (target) => game.user.isGM && OptionsAvancees.isUsing(EXPORT_CSV_SCRIPTARIUM) && @@ -59,12 +58,12 @@ export class ExportScriptarium { } getHeaderLine() { - return this.mapping.map(it => it.column) + return Mapping.getColumns() } getActorLine(actor) { - const context = Mapping.prepareContext(actor) - return this.mapping.map(it => it.getter(actor, context)) + const values = Mapping.getValues(actor) + return values .map(it => this.$escapeQuotes(it)) .map(it => it.replaceAll("\n", " ").replaceAll("\r", "")) } diff --git a/module/actor/export-scriptarium/mapping.js b/module/actor/export-scriptarium/mapping.js index 5f8d6237..e0e7a7d7 100644 --- a/module/actor/export-scriptarium/mapping.js +++ b/module/actor/export-scriptarium/mapping.js @@ -6,6 +6,7 @@ import { ITEM_TYPES } from "../../item.js" import { Misc } from "../../misc.js" import { RdDTimestamp } from "../../time/rdd-timestamp.js" import { RdDBonus } from "../../rdd-bonus.js" +import { TMRType } from "../../tmr-utility.js" const CATEGORIES_COMPETENCES = [ @@ -37,11 +38,11 @@ const NIVEAU_BASE = { class ColumnMappingFactory { static createMappingArme(part, i) { - return { column: `arme-${part}-${i}`, getter: (actor, context) => Mapping.getArme(actor, context, 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) } + return { column: `sort_${part}_${i}`, getter: (actor, context) => Mapping.getSort(actor, context, part, i) } } } @@ -51,40 +52,40 @@ 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: "ID", colName: 'ID', getter: (actor, context) => actor.id }, { column: "name", getter: (actor, context) => actor.name }, - { column: "metier", getter: (actor, context) => actor.system.metier }, - // { column: "biographie", getter: (actor, context) => actor.system.biographie }, + { column: "metier", colName: 'Métier', getter: (actor, context) => actor.system.metier }, + { column: "biographie", colName: '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: "agilite", colName: 'Agilité', getter: (actor, context) => actor.system.carac.agilite.value }, + { column: "dexterite", colName: 'Dextérité', 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: "ouie", colName: 'Ouïe', getter: (actor, context) => actor.system.carac.ouie.value }, + { column: "odoratgout", colName: 'Odo-goût', getter: (actor, context) => actor.system.carac.odoratgout.value }, + { column: "volonte", colName: 'Volonté', 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: "reve", colName: 'Rêve', 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: "melee", colName: 'Mêlée', 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: "derobee", colName: 'Dérobée', 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: "plusdom", colName: '+dom', getter: (actor, context) => actor.system.attributs.plusdom.value }, + { column: "protectionnaturelle", colName: 'Protection naturelle', getter: (actor, context) => actor.system.attributs.protection.value > 0 ? 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: "malus_armure", getter: (actor, context) => Mapping.getMalusArmure(actor, context) }, { column: "esquive", getter: (actor, context) => Mapping.getEsquive(context) }, - { column: "esquive-armure", getter: (actor, context) => Mapping.getEsquiveArmure(context) }, + { column: "esquive_armure", getter: (actor, context) => Mapping.getEsquiveArmure(context) }, { column: "competences", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_COMPETENCES) }, - { column: "draconic", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_DRACONIC) }, + { column: "draconic", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_DRACONIC) }, ] const MAPPING_ARMES = TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('name', i)) @@ -104,6 +105,27 @@ export class Mapping { return MAPPING } + static getColumns() { + return MAPPING.map(it => it.column) + } + + static getValues(actor) { + const context = Mapping.prepareContext(actor) + return MAPPING.map(it => it.getter(actor, context)) + } + static getAsObject(actor) { + const context = Mapping.prepareContext(actor) + return Object.fromEntries(MAPPING.map(it => [it.column, { + colName: it.colName ?? it.column, + value: it.getter(actor, context) + }])) + } + + static getValues(actor) { + const context = Mapping.prepareContext(actor) + return MAPPING.map(it => it.getter(actor, context)) + } + static prepareContext(actor) { return { armes: Mapping.prepareArmes(actor), @@ -190,12 +212,16 @@ export class Mapping { } static prepareSorts(actor) { - return actor.itemTypes[ITEM_TYPES.sort].map(it => Mapping.prepareSort(it)) + const codeVoies = Mapping.getCompetencesCategorie(actor, CATEGORIES_DRACONIC) + .map(it => RdDItemSort.getVoieCode(it)) + + return actor.itemTypes[ITEM_TYPES.sort].map(it => Mapping.prepareSort(it, codeVoies)) + .sort(Misc.ascending(it => `${it.voie} : ${it.description}`)) } - static prepareSort(sort) { + static prepareSort(sort, voies) { return { - voie: RdDItemSort.getCodeDraconic(sort), + voie: RdDItemSort.getCodeDraconic(sort, voies), description: Mapping.descriptionSort(sort), bonus: Mapping.bonusCase(sort) } @@ -203,8 +229,18 @@ export class Mapping { 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}` + const caseTMR = sort.system.caseTMRspeciale.length > 0 ? Mapping.toVar(sort.system.caseTMRspeciale) : Misc.upperFirst(TMRType[sort.system.caseTMR].name) + const ptreve = Mapping.addSpaceToNonNumeric(sort.system.ptreve) + const diff = Mapping.addSpaceToNonNumeric(sort.system.difficulte) + return `${sort.name}${ptSeuil} (${caseTMR}) R${diff} r${ptreve}` + } + + static addSpaceToNonNumeric(value) { + return Number.isNumeric(value) ? value : ' ' + Mapping.toVar(value) + } + + static toVar(value) { + return value.replace('variable', 'var') } static bonusCase(sort) { @@ -237,7 +273,14 @@ export class Mapping { } static getProtectionArmure(actor, context) { - return Number(context?.armure?.protection ?? 0) + Number(actor.system.attributs.protection.value) + const protection = Number(actor.system.attributs.protection.value) + if (context?.armure?.protection == undefined) { + return protection + } + if (Number.isNumeric(context?.armure?.protection)) { + return Number(context?.armure?.protection ?? 0) + protection + } + return context?.armure.protection + (protection > 0 ? `+${protection}` : '') } static getMalusArmure(actor, context) { diff --git a/module/item-sort.js b/module/item-sort.js index be1a2f66..0baf8e5e 100644 --- a/module/item-sort.js +++ b/module/item-sort.js @@ -5,12 +5,12 @@ import { Misc } from "./misc.js"; import { TMRUtility } from "./tmr-utility.js"; const VOIES_DRACONIC = [ - { code: 'O', label: "Voie d'Oniros", short: 'Oniros' }, - { code: 'H', label: "Voie d'Hypnos", short: 'Hypnos' }, - { code: 'N', label: "Voie de Narcos", short: 'Narcos' }, - { code: 'T', label: "Voie de Thanatos", short: 'Thanatos' }, - { code: 'O/H/N/T', label: "Oniros/Hypnos/Narcos/Thanatos", short: 'Oniros/Hypnos/Narcos/Thanatos' }, - { code: 'O/H/N', label: "Oniros/Hypnos/Narcos" } + { code: 'O', label: "Voie d'Oniros", short: 'Oniros', ordre: 'a' }, + { code: 'H', label: "Voie d'Hypnos", short: 'Hypnos', ordre: 'b' }, + { code: 'N', label: "Voie de Narcos", short: 'Narcos', ordre: 'c' }, + { code: 'T', label: "Voie de Thanatos", short: 'Thanatos', ordre: 'd' }, + { code: 'O/H/N/T', label: "Oniros/Hypnos/Narcos/Thanatos", short: 'Oniros/Hypnos/Narcos/Thanatos', ordre: 'e' }, + { code: 'O/H/N', label: "Oniros/Hypnos/Narcos", short: "Oniros/Hypnos/Narcos", ordre: 'f' } ] /* -------------------------------------------- */ @@ -27,17 +27,33 @@ export class RdDItemSort extends Item { return [RdDItemCompetence.getVoieDraconic(draconicList, sort.system.draconic)]; } - static getCodeDraconic(sort) { + static getOrdreCode(code) { + return (VOIES_DRACONIC.find(it => it.code == code)?.ordre ?? '?') + } + + static getVoieCode(voie) { + return VOIES_DRACONIC.find(it => voie.name.includes(it.short))?.code ?? '?' + } + + static getCodeDraconic(sort, voies = ['O', 'H', 'N', 'T']) { switch (Grammar.toLowerCaseNoAccent(sort.name)) { case "lecture d'aura": case "detection d'aura": - return 'O/H/N/T' + return RdDItemSort.$voiesConnues('O/H/N/T', voies) case "annulation de magie": - return 'O/H/N' + return RdDItemSort.$voiesConnues('O/H/N', voies) } const voie = VOIES_DRACONIC.find(it => it.label.includes(sort.system.draconic)) return voie?.code ?? sort.system.draconic } + + + static $voiesConnues(voiesSort, voies) { + const codes = voies.filter(it => voiesSort.includes(it)) + .sort(Misc.ascending(it => RdDItemSort.getOrdreCode(it))) + return Misc.join(codes ?? [''], '/'); + } + /* -------------------------------------------- */ static isDifficulteVariable(sort) { return sort && (sort.system.difficulte.toLowerCase() == "variable"); @@ -67,7 +83,7 @@ export class RdDItemSort extends Item { static buildBonusCaseList(bonuscase, newCase) { const list = RdDItemSort.bonuscaseStringToList(bonuscase) if (newCase) { - list.push({ case: "Nouvelle", bonus: 0 }) + list.push({ case: "Nouvelle", bonus: 0 }) } return list; } diff --git a/module/rdd-main.js b/module/rdd-main.js index 36e090fc..4e955e53 100644 --- a/module/rdd-main.js +++ b/module/rdd-main.js @@ -68,6 +68,7 @@ import { RdDTMRDialog } from "./rdd-tmr-dialog.js" import { OptionsAvancees } from "./settings/options-avancees.js" import { ExportScriptarium } from "./actor/export-scriptarium/export-scriptarium.js" import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js" +import { RdDActorExportSheet } from "./actor/export-scriptarium/actor-export-sheet.js" /** * RdD system @@ -160,12 +161,12 @@ export class SystemReveDeDragon { // Register sheet application classes Actors.unregisterSheet("core", ActorSheet) Actors.registerSheet(SYSTEM_RDD, RdDCommerceSheet, { types: ["commerce"], makeDefault: true }) - //Actors.registerSheet(SYSTEM_RDD, RdDActorExportSheet, { types: ["personnage"], makeDefault: false }) Actors.registerSheet(SYSTEM_RDD, RdDActorSheet, { types: ["personnage"], makeDefault: true }) Actors.registerSheet(SYSTEM_RDD, RdDCreatureSheet, { types: ["creature"], makeDefault: true }) Actors.registerSheet(SYSTEM_RDD, RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true }) Actors.registerSheet(SYSTEM_RDD, RdDActorEntiteSheet, { types: ["entite"], makeDefault: true }) Items.unregisterSheet("core", ItemSheet) + await RdDActorExportSheet.init() RdDItemSheet.register(RdDSigneDraconiqueItemSheet) RdDItemSheet.register(RdDRencontreItemSheet) diff --git a/styles/simple.css b/styles/simple.css index 77a3b277..9e5d6299 100644 --- a/styles/simple.css +++ b/styles/simple.css @@ -326,7 +326,7 @@ table {border: 1px solid #7a7971;} display: grid; grid-column: span 2 / span 2; grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 10px; + gap: 30px; margin: 10px 0; padding: 0; } @@ -411,6 +411,11 @@ table {border: 1px solid #7a7971;} text-align: left; } +.flex-group-top { + vertical-align: top; + align-self: start; +} + .flex-group-right { -webkit-box-pack: end; -ms-flex-pack: end; diff --git a/templates/actor/export-scriptarium/actor-export-sheet.hbs b/templates/actor/export-scriptarium/actor-export-sheet.hbs new file mode 100644 index 00000000..90cb7389 --- /dev/null +++ b/templates/actor/export-scriptarium/actor-export-sheet.hbs @@ -0,0 +1,103 @@ +
\ No newline at end of file diff --git a/templates/actor/export-scriptarium/arme.hbs b/templates/actor/export-scriptarium/arme.hbs new file mode 100644 index 00000000..dee9e508 --- /dev/null +++ b/templates/actor/export-scriptarium/arme.hbs @@ -0,0 +1,15 @@ +{{#if name}} +