diff --git a/changelog.md b/changelog.md index fc9a85ac..42d945b1 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,9 @@ # 12.0 +## 12.0.34 - la tête d'Astrobazzarh +- on peut ajouter des liens "jet de dés" dans les descriptions, notes, ... +- les liens "jet de dés" peuvent être utilisés pour un acteur, ou les items de l'acteurs +- les liens "jet de dés" d'"un item non lié à un acteur agit sur les tokens sélectionnés + ## 12.0.33 - la vieillesse d'Astrobazzarh - retour de l'expérience pour les joueurs - suppression du message "Pas de caractéristique" sur les jets d'odorat-goût diff --git a/module/actor-sheet.js b/module/actor-sheet.js index 4436fbcf..c96dfc13 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -19,6 +19,7 @@ import { RdDBaseActorSangSheet } from "./actor/base-actor-sang-sheet.js"; import { RdDCoeur } from "./coeur/rdd-coeur.js"; import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js"; import { RdDItemRace } from "./item/race.js"; +import { RdDTextEditor } from "./apps/rdd-text-roll.js"; /* -------------------------------------------- */ /** @@ -44,8 +45,8 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { cssClass: this.isEditable ? "editable" : "locked", limited: this.actor.limited, owner: this.actor.isOwner, - biographie: await TextEditor.enrichHTML(this.actor.system.biographie, { async: true }), - notes: await TextEditor.enrichHTML(this.actor.system.notes, { async: true }), + biographie: await RdDTextEditor.enrichHTML(this.actor.system.biographie), + notes: await RdDTextEditor.enrichHTML(this.actor.system.notes), }); foundry.utils.mergeObject(formData.calc, { surenc: this.actor.computeMalusSurEncombrement(), diff --git a/module/actor.js b/module/actor.js index 76c5d3b6..ec2ac7cf 100644 --- a/module/actor.js +++ b/module/actor.js @@ -17,7 +17,7 @@ import { RdDItemSigneDraconique } from "./item/signedraconique.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { EffetsDraconiques } from "./tmr/effets-draconiques.js"; import { Draconique } from "./tmr/draconique.js"; -import { LIST_CARAC, RdDCarac } from "./rdd-carac.js"; +import { LIST_CARAC_PERSONNAGE, RdDCarac } from "./rdd-carac.js"; import { DialogConsommer } from "./dialog-item-consommer.js"; import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js"; import { RollDataAjustements } from "./rolldata-ajustements.js"; @@ -662,15 +662,15 @@ export class RdDActor extends RdDBaseActorSang { /* -------------------------------------------- */ async updateCarac(caracName, to) { to = Number(to) - if (!RdDItemRace.checkRacialMax(this, caracName, to)){ + if (!RdDItemRace.checkRacialMax(this, caracName, to)) { return } - if (caracName == LIST_CARAC.reve.code) { + if (caracName == LIST_CARAC_PERSONNAGE.reve.code) { if (to > Misc.toInt(this.system.reve.seuil.value)) { this.setPointsDeSeuil(to); } } - if (caracName == LIST_CARAC.chance.code) { + if (caracName == LIST_CARAC_PERSONNAGE.chance.code) { if (to > Misc.toInt(this.system.compteurs.chance.value)) { this.setPointsDeChance(to); } @@ -1387,7 +1387,7 @@ export class RdDActor extends RdDBaseActorSang { } await RdDResolutionTable.rollData(ethylismeData.jetVie); - this._gererExperience(ethylismeData.jetVie); + this.gererExperience(ethylismeData.jetVie); RollDataAjustements.calcul(ethylismeData.jetVie, this); if (ethylismeData.jetVie.rolled.isSuccess) { ethylisme.nb_doses++; @@ -1419,7 +1419,7 @@ export class RdDActor extends RdDBaseActorSang { finalLevel: Number(ethylisme.value) + Number(this.system.compteurs.moral.value) } await RdDResolutionTable.rollData(ethylismeData.jetVolonte); - this._gererExperience(ethylismeData.jetVolonte); + this.gererExperience(ethylismeData.jetVolonte); RollDataAjustements.calcul(ethylismeData.jetVolonte, this); } } @@ -1799,38 +1799,8 @@ export class RdDActor extends RdDBaseActorSang { } } - /** - * Méthode pour faire un jet prédéterminer sans ouvrir la fenêtre de dialogue - * @param {*} caracName - * @param {*} compName - * @param {*} diff - * @param {*} options - * @returns - */ - async doRollCaracCompetence(caracName, compName, diff, options = { title: "" }) { - const carac = this.getCaracByName(caracName); - if (!carac) { - ui.notifications.warn(`${this.name} n'a pas de caractéristique correspondant à ${caracName}`) - return; - } - const competence = this.getCompetence(compName); - let rollData = { - alias: this.getAlias(), - caracValue: Number(carac.value), - selectedCarac: carac, - competence: competence, - diffLibre: diff, - show: { title: options?.title ?? '' } - }; - RollDataAjustements.calcul(rollData, this); - await RdDResolutionTable.rollData(rollData); - this._gererExperience(rollData); - await RdDResolutionTable.displayRollData(rollData, this) - return rollData.rolled; - } - /* -------------------------------------------- */ - _gererExperience(rollData) { + gererExperience(rollData) { const callback = this.createCallbackExperience(); if (callback.condition(rollData)) { callback.action(rollData); diff --git a/module/actor/base-actor-reve-sheet.js b/module/actor/base-actor-reve-sheet.js index 996f8f08..6d387ae5 100644 --- a/module/actor/base-actor-reve-sheet.js +++ b/module/actor/base-actor-reve-sheet.js @@ -1,3 +1,4 @@ +import { RdDTextEditor } from "../apps/rdd-text-roll.js"; import { Grammar } from "../grammar.js"; import { ITEM_TYPES } from "../item.js"; import { RdDSheetUtility } from "../rdd-sheet-utility.js"; @@ -47,6 +48,7 @@ export class RdDBaseActorReveSheet extends RdDBaseActorSheet { } }], { renderSheet: true }) ) + this.html.find('.roll-carac-competence').click(async event => await RdDTextEditor.rollText(event, this.actor)) if (this.options.vueDetaillee) { // On carac change diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index 69777d32..bb71912f 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -22,6 +22,7 @@ import { RdDCombat } from "../rdd-combat.js"; import { RdDEmpoignade } from "../rdd-empoignade.js"; import { RdDPossession } from "../rdd-possession.js"; import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, POSSESSION_SANS_DRACONIC } from "../item/base-items.js"; +import { RollDataAjustements } from "../rolldata-ajustements.js"; /** * Classe de base pour les acteurs disposant de rêve (donc, pas des objets) @@ -293,6 +294,38 @@ export class RdDBaseActorReve extends RdDBaseActor { createCallbackAppelAuMoral() { return this.createEmptyCallback(); } async _onCloseRollDialog(html) { } + /** + * Méthode pour faire un jet prédéterminer sans ouvrir la fenêtre de dialogue + * @param {*} caracName code ou label de la caractéristique. On peut utiliser 'intel' pour Intellect. + * @param {*} compName nom de compétence ou nom abrégé. + * @param {*} diff difficulté (0 si undefined) + * @param {*} options + * @returns le jet effectué + */ + async doRollCaracCompetence(caracName, compName, diff, options = { title: "" }) { + const carac = this.getCaracByName(caracName); + if (!carac) { + ui.notifications.warn(`${this.name} n'a pas de caractéristique correspondant à ${caracName}`) + return + } + const competence = this.getCompetence(compName); + let rollData = { + alias: this.getAlias(), + caracValue: Number(carac.value), + selectedCarac: carac, + competence: competence, + diffLibre: diff ?? 0, + show: { title: options?.title ?? '' } + } + RollDataAjustements.calcul(rollData, this); + await RdDResolutionTable.rollData(rollData); + this.gererExperience(rollData); + await RdDResolutionTable.displayRollData(rollData, this) + return rollData.rolled; + } + + gererExperience(rollData) { } + /* -------------------------------------------- */ async roll() { RdDEmpoignade.checkEmpoignadeEnCours(this) diff --git a/module/actor/base-actor-sheet.js b/module/actor/base-actor-sheet.js index 5d88b2f4..96b13827 100644 --- a/module/actor/base-actor-sheet.js +++ b/module/actor/base-actor-sheet.js @@ -5,6 +5,7 @@ import { RdDSheetUtility } from "../rdd-sheet-utility.js"; import { Monnaie } from "../item-monnaie.js"; import { RdDItem, ITEM_TYPES } from "../item.js"; import { RdDItemCompetenceCreature } from "../item-competencecreature.js"; +import { RdDTextEditor } from "../apps/rdd-text-roll.js"; /* -------------------------------------------- */ /** @@ -35,8 +36,8 @@ export class RdDBaseActorSheet extends ActorSheet { img: this.actor.img, name: this.actor.name, system: this.actor.system, - description: await TextEditor.enrichHTML(this.actor.system.description, { async: true }), - notesmj: await TextEditor.enrichHTML(this.actor.system.notesmj, { async: true }), + description: await RdDTextEditor.enrichHTML(this.actor.system.description), + notesmj: await RdDTextEditor.enrichHTML(this.actor.system.notesmj), options: RdDSheetUtility.mergeDocumentRights(this.options, this.actor, this.isEditable), effects: this.actor.effects } diff --git a/module/apps/rdd-text-roll.js b/module/apps/rdd-text-roll.js new file mode 100644 index 00000000..bb9beb11 --- /dev/null +++ b/module/apps/rdd-text-roll.js @@ -0,0 +1,54 @@ +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"; + +const XREGEXP_ROLL = XRegExp("@roll\\[(?[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+)(\\/(?[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+))?(/(?[\\+\\-]?\\d+))?\\]", 'giu') + +export class RdDTextEditor { + static async enrichHTML(text) { + const rddTextEditor = new RdDTextEditor(text) + const replacedRolls = await rddTextEditor.replaceRolls() + return await TextEditor.enrichHTML(replacedRolls, { async: true }) + } + + constructor(text) { + this.original = text + } + + async replaceRolls() { + if (!this.updated) { + this.updated = this.original + await XRegExp.forEach(this.original, XREGEXP_ROLL, async (rollMatch, i) => await this._replaceOneRoll(rollMatch)) + } + return this.updated + } + + async _replaceOneRoll(rollMatch) { + const carac = RdDCarac.caracDetails(rollMatch.carac); + const competence = rollMatch.competence ? RdDItemCompetence.findCompetence(await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage), + rollMatch.competence) : undefined + + if (carac) { + + const replacement = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/apps/link-text-roll.hbs`, { + carac: carac, + competence: competence?.name, + diff: rollMatch.diff + }); + this.updated = this.updated.replace(rollMatch[0], replacement); + } + } + + static async rollText(event, actor) { + const caracCode = event.currentTarget.attributes['data-carac-code'].value; + const competence = event.currentTarget.attributes['data-competence']?.value; + const diff = event.currentTarget.attributes['data-diff']?.value + + const path = RdDCarac.caracDetails(caracCode)?.path + const actors = actor ? [actor] : canvas.tokens.controlled.map(it => it.actor).filter(it => it) + actors.filter(it => foundry.utils.getProperty(it, path) != undefined) + .forEach(it => it.doRollCaracCompetence(caracCode, competence, diff)) + } +} \ No newline at end of file diff --git a/module/apps/xregexp-all.js b/module/apps/xregexp-all.js index 19543a64..9655338b 100644 --- a/module/apps/xregexp-all.js +++ b/module/apps/xregexp-all.js @@ -2002,7 +2002,7 @@ XRegExp.exec = function (str, regex, pos, sticky) { */ -XRegExp.forEach = function (str, regex, callback) { +XRegExp.forEach = async function (str, regex, callback) { var pos = 0; var i = -1; var match; @@ -2014,7 +2014,7 @@ XRegExp.forEach = function (str, regex, callback) { // at least. Actually, because of the way `XRegExp.exec` caches globalized versions of // regexes, mutating the regex will not have any effect on the iteration or matched strings, // which is a nice side effect that brings extra safety. - callback(match, ++i, str, regex); + await callback(match, ++i, str, regex); pos = match.index + (match[0].length || 1); } }; diff --git a/module/item-sheet.js b/module/item-sheet.js index e25aaddd..90c3c339 100644 --- a/module/item-sheet.js +++ b/module/item-sheet.js @@ -12,8 +12,9 @@ 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 { ACTOR_TYPES, ITEM_TYPES, RdDItem } from "./item.js"; import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js"; +import { RdDTextEditor } from "./apps/rdd-text-roll.js"; /** * Extend the basic ItemSheet for RdD specific items @@ -97,11 +98,11 @@ export class RdDItemSheet extends ItemSheet { 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 }), + description: await RdDTextEditor.enrichHTML(this.item.system.description), + descriptionmj: await RdDTextEditor.enrichHTML(this.item.system.descriptionmj), isComestible: this.item.getUtilisationCuisine(), options: RdDSheetUtility.mergeDocumentRights(this.options, this.item, this.isEditable), - competences: await SystemCompendiums.getCompetences('personnage'), + competences: await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage), categories: RdDItem.getCategories(this.item.type), } @@ -120,18 +121,18 @@ export class RdDItemSheet extends ItemSheet { 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 }) + formData.ingredients = await RdDTextEditor.enrichHTML(this.object.system.ingredients) } 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 }) + formData.extrait = await RdDTextEditor.enrichHTML(this.object.system.extrait) + formData.texte = await RdDTextEditor.enrichHTML(this.object.system.texte) } 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 }) + const manipulation = RdDAlchimie.processManipulation(this.item, this.actor?.id); + formData.manipulation = await RdDTextEditor.enrichHTML(manipulation) + formData.utilisation = await RdDTextEditor.enrichHTML(this.object.system.utilisation) + formData.enchantement = await RdDTextEditor.enrichHTML(this.object.system.enchantement) + formData.sureffet = await RdDTextEditor.enrichHTML(this.object.system.sureffet) } if (this.item.type == ITEM_TYPES.gemme) { formData.gemmeTypeList = RdDGemme.getGemmeTypeOptionList(); @@ -207,6 +208,7 @@ export class RdDItemSheet extends ItemSheet { 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('.roll-carac-competence').click(async event => await RdDTextEditor.rollText(event, this.actor)) this.html.find('.alchimie-tache a').click((event) => { let actor = this._getEventActor(event); if (actor) { @@ -272,7 +274,7 @@ export class RdDItemSheet extends ItemSheet { } } - async supprimerBonusCase(deleteCoord){ + async supprimerBonusCase(deleteCoord) { if (this.item.type == ITEM_TYPES.sort) { const oldList = RdDItemSort.getBonusCaseList(this.item) const newList = oldList.filter(it => it.case != deleteCoord); diff --git a/module/item/race.js b/module/item/race.js index 13fb921e..49216f3a 100644 --- a/module/item/race.js +++ b/module/item/race.js @@ -1,6 +1,6 @@ import { ITEM_TYPES, RdDItem } from "../item.js"; import { Misc } from "../misc.js"; -import { LIST_CARAC, RdDCarac } from "../rdd-carac.js"; +import { LIST_CARAC_PERSONNAGE, RdDCarac } from "../rdd-carac.js"; export class RdDItemRace extends RdDItem { @@ -12,7 +12,7 @@ export class RdDItemRace extends RdDItem { static checkRacialMax(actor, code, value) { const race = RdDItemRace.getRace(actor) - if (code == LIST_CARAC.force.code) { + if (code == LIST_CARAC_PERSONNAGE.force.code) { if (!race.isForceValid(actor, value)) { ui.notifications.warn(race.system.carac.force.limitmessage) return false @@ -55,7 +55,7 @@ export class RdDItemRace extends RdDItem { if (value == undefined) { value = path ? foundry.utils.getProperty(actor, path) : 0 } - if (code == LIST_CARAC.force.code) { + if (code == LIST_CARAC_PERSONNAGE.force.code) { return value >= this.getForceMax(actor) } const max = foundry.utils.getProperty(this, path) ?? -1 diff --git a/module/rdd-alchimie.js b/module/rdd-alchimie.js index 0a58d09d..678f6295 100644 --- a/module/rdd-alchimie.js +++ b/module/rdd-alchimie.js @@ -20,7 +20,7 @@ export class RdDAlchimie { } } } - recette.system.manipulation_update = manip; + return manip; } /* -------------------------------------------- */ diff --git a/module/rdd-carac.js b/module/rdd-carac.js index 29fec0f9..76ad5b88 100644 --- a/module/rdd-carac.js +++ b/module/rdd-carac.js @@ -37,7 +37,7 @@ const TABLE_CARACTERISTIQUES_DERIVEES = { 32: { xp: 180, niveau: 11, poids: "1501-2000", poidsMin: 1501, poidsMax: 2000, plusdom: +11, sconst: 10, sust: 17 } }; -export const LIST_CARAC = { +export const LIST_CARAC_PERSONNAGE = { 'taille': { code: 'taille', label: 'Taille', isCarac: true, path: 'system.carac.taille.value' }, 'apparence': { code: 'apparence', label: 'Apparence', isCarac: true, path: 'system.carac.apparence.value' }, 'constitution': { code: 'constitution', label: 'Constitution', isCarac: true, path: 'system.carac.constitution.value' }, @@ -56,18 +56,43 @@ export const LIST_CARAC = { 'beaute': { code: 'beaute', label: 'Beauté', isCarac: false, path: 'system.background.beaute.value' } } +export const LIST_CARAC_AUTRES = { + 'perception': { code: 'perception', label: 'Perception', path: 'system.carac.perception.value' }, +} + +const LIST_CARAC_DERIVEE = { + 'melee': { code: "melee", label: 'Mêlée', path: 'system.carac.melee.value' }, + 'tir': { code: "tir", label: 'Tir', path: 'system.carac.tir.value' }, + 'lancer': { code: "lancer", label: 'Lancer', path: 'system.carac.lancer.value' }, + 'derobee': { code: "derobee", label: 'Dérobée', path: 'system.carac.derobee.value' }, + 'chance-actuelle': { code: "chance-actuelle", label: 'Chance actuelle', path: 'system.carac.lancer.value' }, + 'reve-actuel': { code: "reve-actuel", label: 'Rêve actuel', path: 'system.reve.reve.value' }, +} + +const LIST_CARAC_ROLL = Object.values(LIST_CARAC_PERSONNAGE).filter(it => it.isCarac && it.code != 'taille') + .concat(Object.values(LIST_CARAC_AUTRES)) + .concat(Object.values(LIST_CARAC_DERIVEE)) + export class RdDCarac { + static caracDetails(name) { + let entry = Misc.findFirstLike(name, LIST_CARAC_ROLL, { mapper: it => it.code, description: 'caractéristique', onMessage: m => { } }) + if (entry && entry.length > 0) { + return entry + } + return Misc.findFirstLike(name, LIST_CARAC_ROLL, { mapper: it => it.label, description: 'caractéristique' }) + } + static carac(code) { - return LIST_CARAC[code] + return LIST_CARAC_PERSONNAGE[code] } static label(code) { - return RdDCarac.carac(code)?.label ?? '---' - } + return RdDCarac.carac(code)?.label ?? '---' + } static caracs(filter = it => it.isCarac) { - return Object.values(LIST_CARAC).filter(filter) + return Object.values(LIST_CARAC_PERSONNAGE).filter(filter) } static isAgiliteOuDerobee(selectedCarac) { diff --git a/template.json b/template.json index 1e617c7e..f1835b56 100644 --- a/template.json +++ b/template.json @@ -3,9 +3,9 @@ "types": ["personnage", "creature", "entite", "commerce", "vehicule"], "templates": { "description": { - "description": "Description ...", + "description": "", "race": "", - "notesmj": "Notes du MJ" + "notesmj": "" }, "subacteurs": { "subacteurs": { diff --git a/templates/apps/link-text-roll.hbs b/templates/apps/link-text-roll.hbs new file mode 100644 index 00000000..2e8c306d --- /dev/null +++ b/templates/apps/link-text-roll.hbs @@ -0,0 +1,8 @@ + +{{~uppercase carac.label~}} +{{#if competence}} / {{upperFirst competence}}{{/if~}} +{{#if diff}} à {{diff}}{{/if~}} + diff --git a/templates/item-recettealchimique-sheet.html b/templates/item-recettealchimique-sheet.html index 08a5f589..af88c741 100644 --- a/templates/item-recettealchimique-sheet.html +++ b/templates/item-recettealchimique-sheet.html @@ -9,7 +9,7 @@
- {{editor manipulation_update target="system.manipulation" button=true owner=options.isOwner editable=options.editable engine="prosemirror"}} + {{editor manipulation target="system.manipulation" button=true owner=options.isOwner editable=options.editable engine="prosemirror"}}