From d53da1f01157d04e3533284be2711bbace8e0081 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 12 Jan 2025 02:38:31 +0100 Subject: [PATCH] Jets d'alchimie dans descriptions/journaux On ne se limite plus aux manipulations alchimiques, et les jets apparaissent comme tous les autres types de jets --- changelog.md | 2 + module/apps/rdd-import-stats.js | 1 - module/apps/rdd-text-roll.js | 130 ++++++++++++++---- module/item-sheet.js | 15 +- module/rdd-alchimie.js | 45 +----- styles/simple.css | 9 +- templates/apps/link-text-roll-alchimie.hbs | 8 ++ .../apps/link-text-roll-carac-competence.hbs | 1 + templates/apps/link-text-roll-foundry.hbs | 4 +- 9 files changed, 129 insertions(+), 86 deletions(-) create mode 100644 templates/apps/link-text-roll-alchimie.hbs diff --git a/changelog.md b/changelog.md index 3eeb282d..cfcb7cbc 100644 --- a/changelog.md +++ b/changelog.md @@ -10,6 +10,8 @@ - gestion des blocs secrets dans les descriptions - on peut ajouter des liens "jet de dés" pour appeler une formule dés de foundry +- les liens "manipulation alchimiques" peuvent être dans les descriptions, notes, ... +- les "manipulation alchimiques" fonctionnent comme tous les autres jets ## 12.0.33 - la vieillesse d'Astrobazzarh diff --git a/module/apps/rdd-import-stats.js b/module/apps/rdd-import-stats.js index 78ea64ed..d07cdc39 100644 --- a/module/apps/rdd-import-stats.js +++ b/module/apps/rdd-import-stats.js @@ -34,7 +34,6 @@ const XREGEXP_WEAPON_MANIEMENT = "(?(" + Misc.join(Object.keys(MANIEM const XREGEXP_SORT_VOIE = "(?[OHNT](\\/[OHNT])*)" const XREGEXP_SORT_NAME = "(?[^\\(]+)" -// const XREGEXP_SORT_CASE = "(?([A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+|[A-M]\\d{1,2})+)" const XREGEXP_SORT_CASE = "(?([A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+|[A-M]\\d{1,2}))" const XREGEXP_SORT = "(" + XREGEXP_SORT_VOIE diff --git a/module/apps/rdd-text-roll.js b/module/apps/rdd-text-roll.js index e8c47af7..c0249edf 100644 --- a/module/apps/rdd-text-roll.js +++ b/module/apps/rdd-text-roll.js @@ -2,8 +2,15 @@ import "./xregexp-all.js"; import { RdDCarac } from "../rdd-carac.js"; import { SystemCompendiums } from "../settings/system-compendiums.js"; import { RdDItemCompetence } from "../item-competence.js"; -import { ACTOR_TYPES } from "../item.js"; +import { ACTOR_TYPES, ITEM_TYPES } from "../item.js"; import { RdDUtility } from "../rdd-utility.js"; +import { Misc } from "../misc.js"; +import { RdDAlchimie } from "../rdd-alchimie.js"; + +const REGEX_ALCHIMIE_TERMES = "(?(\\w|-)+)" +const REGEX_ALCHIMIE_MANIP = "(?(couleur|consistance))" +const XREGEXP_ROLL_ALCHIMIE = XRegExp("@roll\\[" + REGEX_ALCHIMIE_MANIP + "\\s+" + REGEX_ALCHIMIE_TERMES + "\\]", 'giu') +const XREGEXP_ROLL_ALCHIMIE_MANIP = XRegExp("@" + REGEX_ALCHIMIE_MANIP + "\\{" + REGEX_ALCHIMIE_TERMES + "\\}", 'giu') const REGEXP_ROLL_CARAC_COMP = "(?[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+)(\\/(?[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+))?(/(?[\\+\\-]?\\d+))?" const XREGEXP_ROLL_CARAC_COMP = XRegExp("@roll\\[" + REGEXP_ROLL_CARAC_COMP + "\\]", 'giu') @@ -11,42 +18,109 @@ const XREGEXP_ROLL_CARAC_COMP = XRegExp("@roll\\[" + REGEXP_ROLL_CARAC_COMP + "\ const REGEXP_ROLL_FORMULA = "(?[^\\[\\]]+)" const XREGEXP_ROLL_FORMULA = XRegExp("@roll\\[" + REGEXP_ROLL_FORMULA + "\\]", 'giu') + +/** + * classe pour gérer les jets d'alchimie + */ +class TextRollAlchimie { + static async onRollText(event, actor) { + actor = TextRollAlchimie.getSelectedActor(actor) + if (actor) { + const recetteId = event.currentTarget.attributes['data-recette-id']?.value + const manip = event.currentTarget.attributes['data-manip'].value + const termes = event.currentTarget.attributes['data-termes'].value + if (recetteId) { + await actor.effectuerTacheAlchimie(recetteId, manip, termes) + } + else { + const carac = RdDCarac.caracDetails(RdDAlchimie.getCaracTache(manip)) + const diff = RdDAlchimie.getDifficulte(termes) + await actor.rollCaracCompetence(carac.code, 'Alchimie', diff) + } + } + } + + static getSelectedActor(actor) { + actor = actor ?? RdDUtility.getSelectedActor() + if (actor && actor.type == ACTOR_TYPES.personnage) { + return actor + } + return undefined + } + + static async onReplaceRoll(context) { + const handler = new TextRollAlchimie(context) + context.text = await handler.replaceManipulationAlchimie() + } + + constructor(context) { + this.context = context + } + + async replaceManipulationAlchimie() { + await XRegExp.forEach(this.context.text, XREGEXP_ROLL_ALCHIMIE, async (rollMatch, i) => await this._replaceOneAlchimie(rollMatch, i)) + await XRegExp.forEach(this.context.text, XREGEXP_ROLL_ALCHIMIE_MANIP, async (rollMatch, i) => await this._replaceOneAlchimie(rollMatch, i)) + return this.context.text + } + + async _replaceOneAlchimie(rollMatch, i) { + if (rollMatch.termes && rollMatch.manip) { + const manip = rollMatch.manip + await this._replaceManip(manip, rollMatch, i) + } + } + + async _replaceManip(manip, rollMatch, i) { + const termes = rollMatch.termes + const carac = RdDCarac.caracDetails(RdDAlchimie.getCaracTache(manip)) + const diff = RdDAlchimie.getDifficulte(termes) + const recette = (this.context.object instanceof Item && this.context.object.type == ITEM_TYPES.recettealchimique) ? this.context.object : undefined + const replacement = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/apps/link-text-roll-alchimie.hbs`, { + manip, + termes, + recette, + carac, + diff + }) + this.context.text = this.context.text.replace(rollMatch[0], replacement); + } +} + /** * classe pour gérer les jets de caractéristique/compétence depuis * les journaux/descriptions */ class TextRollCaracCompetence { - static async onReplaceRoll(context) { - const competences = await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage); - const handler = new TextRollCaracCompetence(context.text, competences) - context.text = await handler.replaceRollCaracCompetence() - } - static async onRollText(event, actor) { - const caracCode = event.currentTarget.attributes['data-carac-code']?.value + const caracCode = event.currentTarget.attributes['data-carac-code']?.value if (caracCode) { const competence = event.currentTarget.attributes['data-competence']?.value const diff = event.currentTarget.attributes['data-diff']?.value const actors = TextRollCaracCompetence.getSelectedActors(actor) - actors.forEach(it => TextRollCaracCompetence.doRoll(it, caracCode, competence, diff)) + actors.forEach(async it => await TextRollCaracCompetence.doRoll(it, caracCode, competence, diff)) } } static async doRoll(actor, caracCode, competence, diff) { caracCode = actor.mapCarac(caracCode) if (competence) { if (actor.type == ACTOR_TYPES.personnage) { - actor.rollCaracCompetence(caracCode, competence, diff) + await actor.rollCaracCompetence(caracCode, competence, diff) } else { - actor.doRollCaracCompetence(caracCode, competence, diff) + await actor.doRollCaracCompetence(caracCode, competence, diff) } } else { - actor.rollCarac(caracCode, { diff }) + await actor.rollCarac(caracCode, { diff }) } } + static async onReplaceRoll(context) { + const handler = new TextRollCaracCompetence(context) + context.text = await handler.replaceRollCaracCompetence() + } + static getSelectedActors(actor) { const selected = canvas.tokens.controlled.map(it => it.actor).filter(it => it) if (selected.length > 0) { @@ -59,30 +133,32 @@ class TextRollCaracCompetence { return [] } - constructor(text, competences) { - this.text = text - this.competences = competences + constructor(context) { + this.context = context } async replaceRollCaracCompetence() { - await XRegExp.forEach(this.text, XREGEXP_ROLL_CARAC_COMP, async (rollMatch, i) => await this._replaceOne(rollMatch, i)) - return this.text + await XRegExp.forEach(this.context.text, XREGEXP_ROLL_CARAC_COMP, async (rollMatch, i) => await this._replaceOne(rollMatch, i)) + return this.context.text } async _replaceOne(rollMatch, i) { const carac = RdDCarac.caracDetails(rollMatch.carac) if (carac) { - const competence = rollMatch.competence ? RdDItemCompetence.findCompetence(this.competences, rollMatch.competence) : undefined + const competence = rollMatch.competence ? RdDItemCompetence.findCompetence(this.context.competences, rollMatch.competence) : undefined const replacement = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/apps/link-text-roll-carac-competence.hbs`, { carac: carac, competence: competence?.name, diff: rollMatch.diff }) - this.text = this.text.replace(rollMatch[0], replacement) + this.context.text = this.context.text.replace(rollMatch[0], replacement) } } } +/** + * classe pour gérer les jets de dés (formules Foundry) + */ class TextRollFoundry { static async onReplaceRoll(context) { @@ -118,11 +194,12 @@ class TextRollFoundry { } } - export class RdDTextEditor { static async enrichHTML(text, object) { - const context = { text } + const competences = await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage); + const context = { text, competences, object } + await TextRollAlchimie.onReplaceRoll(context) await TextRollCaracCompetence.onReplaceRoll(context) await TextRollFoundry.onReplaceRoll(context) return await TextEditor.enrichHTML(context.text, { @@ -133,8 +210,15 @@ export class RdDTextEditor { } static async rollText(event, actor) { - await TextRollCaracCompetence.onRollText(event, actor) - await TextRollFoundry.onRollText(event, actor) + const rollMode = event.currentTarget.attributes['data-roll-mode']?.value; + switch (rollMode) { + case 'foundry': + return await TextRollFoundry.onRollText(event, actor) + case 'carac': + return await TextRollCaracCompetence.onRollText(event, actor) + case 'alchimie': + return await TextRollAlchimie.onRollText(event, actor) + } } } \ No newline at end of file diff --git a/module/item-sheet.js b/module/item-sheet.js index 13cf5e91..4fe2838d 100644 --- a/module/item-sheet.js +++ b/module/item-sheet.js @@ -1,6 +1,5 @@ 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"; @@ -128,8 +127,7 @@ export class RdDItemSheet extends ItemSheet { formData.texte = await RdDTextEditor.enrichHTML(this.item.system.texte, this.item) } if (this.item.type == ITEM_TYPES.recettealchimique) { - const manipulation = RdDAlchimie.processManipulation(this.item, this.actor?.id); - formData.manipulation = await RdDTextEditor.enrichHTML(manipulation, this.item) + formData.manipulation = await RdDTextEditor.enrichHTML(this.item.system.manipulation, this.item) formData.utilisation = await RdDTextEditor.enrichHTML(this.item.system.utilisation, this.item) formData.enchantement = await RdDTextEditor.enrichHTML(this.item.system.enchantement, this.item) formData.sureffet = await RdDTextEditor.enrichHTML(this.item.system.sureffet, this.item) @@ -209,17 +207,6 @@ export class RdDItemSheet extends ItemSheet { 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('.roll-text').click(async event => await RdDTextEditor.rollText(event, this.actor)) - 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())); diff --git a/module/rdd-alchimie.js b/module/rdd-alchimie.js index 678f6295..66bb6ec3 100644 --- a/module/rdd-alchimie.js +++ b/module/rdd-alchimie.js @@ -1,48 +1,8 @@ -/* -------------------------------------------- */ import { Misc } from "./misc.js"; -const matchOperations = new RegExp(/@(\w*){([\w\-]+)}/ig); -const matchOperationTerms = new RegExp(/@(\w*){([\w\-]+)}/i); -/* -------------------------------------------- */ export class RdDAlchimie { - - /* -------------------------------------------- */ - static processManipulation(recette, actorId = undefined) { - let manip = recette.system.manipulation; - let matchArray = manip.match(matchOperations); - if (matchArray) { - for (let matchStr of matchArray) { - let result = matchStr.match(matchOperationTerms); - if (result[1] && result[2]) { - let commande = Misc.upperFirst(result[1]); - let replacement = this[`_alchimie${commande}`](recette, result[2], actorId); - manip = manip.replace(result[0], replacement); - } - } - } - return manip; - } - - /* -------------------------------------------- */ - static _alchimieCouleur(recette, couleurs, actorId) { - return RdDAlchimie._alchimieLink(recette, couleurs, actorId, 'couleur', 'Température'); - } - - /* -------------------------------------------- */ - static _alchimieConsistance(recette, consistances, actorId) { - return RdDAlchimie._alchimieLink(recette, consistances, actorId, 'consistance', 'Consistance'); - } - - static _alchimieLink(recette, termes, actorId, tacheAlchimie, labelTache) { - const difficulte = RdDAlchimie.getDifficulte(termes); - const link = actorId ? ` ` : ''; - const endLink = actorId ? '' : ''; - return `${link}${labelTache} ${termes} (${difficulte})${endLink}`; - } - - /* -------------------------------------------- */ - static getDifficulte(aspects) { - let elements = aspects.split('-'); + static getDifficulte(termes) { + let elements = termes.split('-'); let composantes = elements.length; let distincts = Object.keys(Misc.classifyFirst(elements, it => it)).length; if (distincts == 1) { @@ -58,5 +18,4 @@ export class RdDAlchimie { } return 'intellect'; } - } diff --git a/styles/simple.css b/styles/simple.css index 78b2d63e..01525844 100644 --- a/styles/simple.css +++ b/styles/simple.css @@ -1067,12 +1067,13 @@ li label.compteur { max-width: 90%; } -.alchimie-tache { +a.roll-text.content-link { + color: hsla(300, 70%, 40%, 0.5); font-weight: bold; - background: rgb(182, 180, 179); - border: 1px solid rgba(72, 46, 28, 1); + border: 1px solid var(--color-border-dark-tertiary); border-radius: 0.25rem; - color: rgba(212, 27, 27, 0.5); + white-space: nowrap; + word-break: break-all; } .window-app.sheet .window-content .tooltip:hover .tooltiptext { diff --git a/templates/apps/link-text-roll-alchimie.hbs b/templates/apps/link-text-roll-alchimie.hbs new file mode 100644 index 00000000..e52fd8d3 --- /dev/null +++ b/templates/apps/link-text-roll-alchimie.hbs @@ -0,0 +1,8 @@ + +{{~manip}} {{termes~}} + diff --git a/templates/apps/link-text-roll-carac-competence.hbs b/templates/apps/link-text-roll-carac-competence.hbs index 93652db1..e692ad4e 100644 --- a/templates/apps/link-text-roll-carac-competence.hbs +++ b/templates/apps/link-text-roll-carac-competence.hbs @@ -1,4 +1,5 @@ diff --git a/templates/apps/link-text-roll-foundry.hbs b/templates/apps/link-text-roll-foundry.hbs index 7902ab20..2d12f06b 100644 --- a/templates/apps/link-text-roll-foundry.hbs +++ b/templates/apps/link-text-roll-foundry.hbs @@ -1,3 +1,5 @@ - + {{~formula~}}