From 981282d809799660d2f942624e6e1f97c0f8395e Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 27 Nov 2025 23:13:05 +0100 Subject: [PATCH 01/17] =?UTF-8?q?Ajout=20de=20m=C3=A9thode=20getConjuratio?= =?UTF-8?q?ns?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pour lister les compétences de possession/conjuration de manière homogène (tout actor doué de rêve) --- assets/actions/possession.svg | 1 + module/actor.js | 21 +++++++----- module/actor/base-actor-reve.js | 51 +++++++++++++++++++++++++--- module/actor/base-actor-sang.js | 1 + module/actor/entite.js | 7 ---- module/constants.js | 1 + module/item/arme.js | 4 +++ module/item/base-items.js | 43 ++++++++++++----------- module/rdd-possession.js | 2 +- module/roll/roll-constants.mjs | 5 +-- module/roll/roll-type-possession.mjs | 33 ++++++++++++++++++ 11 files changed, 127 insertions(+), 42 deletions(-) create mode 100644 assets/actions/possession.svg create mode 100644 module/roll/roll-type-possession.mjs diff --git a/assets/actions/possession.svg b/assets/actions/possession.svg new file mode 100644 index 00000000..95b69fa5 --- /dev/null +++ b/assets/actions/possession.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/module/actor.js b/module/actor.js index e76913cd..21bd525e 100644 --- a/module/actor.js +++ b/module/actor.js @@ -19,7 +19,7 @@ import { DialogConsommer } from "./dialog-item-consommer.js"; import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js"; import { RollDataAjustements } from "./rolldata-ajustements-v1.js"; import { RdDPossession } from "./rdd-possession.js"; -import { ACTOR_TYPES, renderTemplate, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; +import { ACTOR_TYPES, RDD_CONFIG, renderTemplate, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; import { RdDConfirm } from "./rdd-confirm.js"; import { DialogRepos } from "./sommeil/dialog-repos.js"; import { RdDBaseActor } from "./actor/base-actor.js"; @@ -41,12 +41,12 @@ import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemSigneDraconique } from "./item/signedraconique.js"; import { RdDRencontre } from "./item/rencontre.js"; import { DialogSelect } from "./dialog-select.js"; -import { PAS_DE_DRACONIC, POSSESSION_SANS_DRACONIC } from "./item/base-items.js"; +import { CATEGORIES_COMPETENCES, PAS_DE_DRACONIC, POSSESSION_SANS_DRACONIC } from "./item/base-items.js"; import { RdDRollResult } from "./rdd-roll-result.js"; import { RdDInitiative } from "./initiative.mjs"; import RollDialog from "./roll/roll-dialog.mjs"; -import { OptionsAvancees, ROLL_DIALOG_V2, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js"; +import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js"; import { ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_SORT } from "./roll/roll-constants.mjs"; import { PART_TACHE } from "./roll/roll-part-tache.mjs"; import { PART_COMP } from "./roll/roll-part-comp.mjs"; @@ -160,12 +160,15 @@ export class RdDActor extends RdDBaseActorSang { /* -------------------------------------------- */ getDemiReve() { return this.system.reve.tmrpos.coord } - getDraconics() { return this.itemTypes[ITEM_TYPES.competence].filter(it => it.system.categorie == 'draconic') } + getDraconics() { + return this.isHautRevant() + ? this.itemTypes[ITEM_TYPES.competence].filter(it => it.system.categorie == CATEGORIES_COMPETENCES.draconic.key) + : [] + } getBestDraconic() { return foundry.utils.duplicate([...this.getDraconics(), PAS_DE_DRACONIC].sort(Misc.descending(it => it.system.niveau)).find(it => true)) } - getDraconicOuPossession() { - return [...this.getDraconics().filter(it => it.system.niveau >= 0), POSSESSION_SANS_DRACONIC] - .sort(Misc.descending(it => it.system.niveau)) - .find(it => true) + + getConjurationNaturelle() { + return new RdDItemCompetence(POSSESSION_SANS_DRACONIC) } isForceInsuffisante(forceRequise) { @@ -688,7 +691,7 @@ export class RdDActor extends RdDBaseActorSang { const rencontre = await game.system.rdd.rencontresTMR.getReveDeDragon(force); let rollData = { actor: this, - competence: this.getDraconicOuPossession(), + competence: this.getDraconicOuPossession().find(it => true), canClose: false, rencontre: rencontre, tmr: true, diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index 6a3a0988..b9a50ff4 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -1,4 +1,4 @@ -import { renderTemplate, SHOW_DICE, SYSTEM_RDD } from "../constants.js"; +import { RDD_CONFIG, renderTemplate, SHOW_DICE, SYSTEM_RDD } from "../constants.js"; import { Grammar } from "../grammar.js"; import { Misc } from "../misc.js"; import { RdDResolutionTable } from "../rdd-resolution-table.js"; @@ -22,13 +22,15 @@ import { DialogValidationEncaissement } from "../dialog-validation-encaissement. 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 { BASE_CORPS_A_CORPS, BASE_ESQUIVE, CATEGORIES_COMPETENCES_CREATURES } from "../item/base-items.js"; import { RollDataAjustements } from "../rolldata-ajustements-v1.js"; import { MappingCreatureArme } from "../item/mapping-creature-arme.mjs"; import RollDialog from "../roll/roll-dialog.mjs"; import { ATTAQUE_ROLL_TYPES, DEFAULT_ROLL_TYPES, DIFF, DIFFS, ROLL_TYPE_ATTAQUE, ROLL_TYPE_COMP, ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_OEUVRE, ROLL_TYPE_TACHE } from "../roll/roll-constants.mjs"; import { OptionsAvancees, ROLL_DIALOG_V2 } from "../settings/options-avancees.js"; import { PART_COMP } from "../roll/roll-part-comp.mjs"; +import { RdDInitiative } from "../initiative.mjs"; +import { RdDItemCompetenceCreature } from "../item-competencecreature.js"; /** * Classe de base pour les acteurs disposant de rêve (donc, pas des objets) @@ -114,6 +116,49 @@ export class RdDBaseActorReve extends RdDBaseActor { return this.system.carac[competence.system.defaut_carac].value; } + getDraconics() { return [] } + getDraconicOuPossession() { + return [ + ...this.getDraconics(), + ...this.itemTypes[ITEM_TYPES.competencecreature].filter(it => it.system.ispossession || it.system.categorie == CATEGORIES_COMPETENCES_CREATURES.possession.key), + this.getConjurationNaturelle() + ].sort(Misc.descending(it => it.system.niveau)); + } + + getConjurations() { + return this.getDraconicOuPossession() + .map(it => this.toActionConjuration(it)) + } + + getConjurationNaturelle() { + return new RdDItemCompetenceCreature({ + name: 'Sans compétence', + type: ITEM_TYPES.competencecreature, + img: RDD_CONFIG.icons.possession, + system: { + carac_value: this.getReveActuel(), + niveau: 0, + default_diffLibre: 0, + categorie: CATEGORIES_COMPETENCES_CREATURES.possession.key, + ispossession: true, + } + }) + } + + toActionConjuration(comp) { + const caracCode = this.isPersonnage() ? CARACS.REVE_ACTUEL : CARACS.REVE + const caracValue = this.getReveActuel() + const ajustement = this.getEtatGeneral() + return { + label: `Conjuration (${comp.name})`, + action: 'possession', + initOnly: false, + comp: comp, + carac: { key: caracCode, value: caracValue }, + initiative: RdDInitiative.getRollInitiative(caracValue, comp.system.niveau, ajustement) + } + } + listActions({ isAttaque = false, isEquipe = false }) { return this.itemTypes[ITEM_TYPES.competencecreature] .filter(it => it.isAttaque()) @@ -198,8 +243,6 @@ export class RdDBaseActorReve extends RdDBaseActor { return false } - getDraconicOuPossession() { return POSSESSION_SANS_DRACONIC } - getPossession(possessionId) { return this.itemTypes[ITEM_TYPES.possession].find(it => it.system.possessionid == possessionId); } diff --git a/module/actor/base-actor-sang.js b/module/actor/base-actor-sang.js index 74bcc4f5..07922963 100644 --- a/module/actor/base-actor-sang.js +++ b/module/actor/base-actor-sang.js @@ -7,6 +7,7 @@ import { RdDDice } from "../rdd-dice.js"; import { RdDItemBlessure } from "../item/blessure.js"; import { ChatUtility } from "../chat-utility.js"; import { Misc } from "../misc.js"; +import { CARACS } from "../rdd-carac.js"; /** * Classe de base pour les acteurs qui peuvent subir des blessures diff --git a/module/actor/entite.js b/module/actor/entite.js index 17eef287..a005fd28 100644 --- a/module/actor/entite.js +++ b/module/actor/entite.js @@ -41,13 +41,6 @@ export class RdDEntite extends RdDBaseActorReve { getChance() { return this.getReve() } getEnduranceMax() { return Math.max(1, this.getTaille() + this.getReve()) } - getDraconicOuPossession() { - return this.itemTypes[ITEM_TYPES.competencecreature] - .filter(it => it.system.categorie == 'possession') - .sort(Misc.descending(it => it.system.niveau)) - .find(it => true); - } - async remiseANeuf() { if (!this.isEntiteNonIncarnee()) { await this.update({ diff --git a/module/constants.js b/module/constants.js index e90ea3f1..9ec0d44b 100644 --- a/module/constants.js +++ b/module/constants.js @@ -61,6 +61,7 @@ export const RDD_CONFIG = { armesDisparates: 'systems/foundryvtt-reve-de-dragon/assets/actions/armes-disparates.svg', demiReve: 'systems/foundryvtt-reve-de-dragon/assets/actions/sort.svg', empoignade: 'systems/foundryvtt-reve-de-dragon/assets/actions/empoignade.svg', + possession: 'systems/foundryvtt-reve-de-dragon/assets/actions/possession.svg', forceWeak: 'systems/foundryvtt-reve-de-dragon/assets/actions/weak.svg', surenc: 'systems/foundryvtt-reve-de-dragon/assets/actions/surenc.svg', magique: 'systems/foundryvtt-reve-de-dragon/assets/actions/magique.svg', diff --git a/module/item/arme.js b/module/item/arme.js index 2e3ccced..204a7cd9 100644 --- a/module/item/arme.js +++ b/module/item/arme.js @@ -278,6 +278,10 @@ export class RdDItemArme extends RdDItem { return this.system.mortalite == RDD_CONFIG.encaissement.empoignade } + isPossession() { + return this.system.mortalite == RDD_CONFIG.encaissement.possession + } + isUtilisableEmpoigne() { return this.system.baseInit == 3 || this.system.baseInit == 4 || this.system.competence == "Dague" } diff --git a/module/item/base-items.js b/module/item/base-items.js index 48bd6ad6..f2ffb854 100644 --- a/module/item/base-items.js +++ b/module/item/base-items.js @@ -1,22 +1,5 @@ -export const POSSESSION_SANS_DRACONIC = { name: 'Sans draconic', type: 'competence', system: { niveau: 0, defaut_carac: "reve-actuel", }, img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp' } -export const PAS_DE_DRACONIC = { name: 'Pas de draconic', type: 'competence', system: { niveau: -11, defaut_carac: "reve" }, img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp' } -export const BASE_CORPS_A_CORPS = { name: 'Corps à Corps', type: 'competence', system: { niveau: -6, defaut_carac: "melee" }, img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp' } -export const BASE_ESQUIVE = { name: 'Esquive', type: 'competence', system: { niveau: -6, defaut_carac: "derobee" }, img: 'systems/foundryvtt-reve-de-dragon/icons/competence_esquive.webp' } - -export const SANS_COMPETENCE = { - name: "Sans compétence", - type: 'competence', - system: { - niveau: 0, - default_diffLibre: 0, - base: 0, - categorie: "Aucune", - description: "", - descriptionmj: "", - defaut_carac: "", - }, - img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp" -} +import { ITEM_TYPES, RDD_CONFIG } from "../constants.js" +import { CARACS } from "../rdd-carac.js" export const CATEGORIES_COMPETENCES = { generale: { key: 'generale', base: -4, label: "Générales" }, @@ -39,3 +22,25 @@ export const CATEGORIES_COMPETENCES_CREATURES = { lancer: { key: 'lancer', base: 0, label: "Lancer" }, possession: { key: 'possession', base: 0, label: "Possession" }, } + +export const POSSESSION_SANS_DRACONIC = { + name: 'Sans draconic', + type: ITEM_TYPES.competence, + img: RDD_CONFIG.icons.possession, + system: { niveau: 0, defaut_carac: CARACS.REVE_ACTUEL, categorie: CATEGORIES_COMPETENCES.draconic.key } +} + +export const PAS_DE_DRACONIC = { name: 'Pas de draconic', type: 'competence', system: { niveau: -11, defaut_carac: "reve" }, img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp' } +export const BASE_CORPS_A_CORPS = { name: 'Corps à Corps', type: 'competence', system: { niveau: -6, defaut_carac: "melee" }, img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp' } +export const BASE_ESQUIVE = { name: 'Esquive', type: 'competence', system: { niveau: -6, defaut_carac: "derobee" }, img: 'systems/foundryvtt-reve-de-dragon/icons/competence_esquive.webp' } + +export const SANS_COMPETENCE = { + name: "Sans compétence", + type: ITEM_TYPES.competence, + img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp", + system: { + niveau: 0, + default_diffLibre: 0, + categorie: CATEGORIES_COMPETENCES.generale.key, + } +} diff --git a/module/rdd-possession.js b/module/rdd-possession.js index bf0b5c85..c8cade05 100644 --- a/module/rdd-possession.js +++ b/module/rdd-possession.js @@ -94,7 +94,7 @@ export class RdDPossession { } static selectCompetenceDraconicOuPossession(rollData, rollingActor) { - rollData.competence = rollingActor.getDraconicOuPossession(); + rollData.competence = rollingActor.getDraconicOuPossession().find(it => true); if (rollingActor.isCreatureOuEntite()) { const carac = rollingActor.system.carac rollData.carac = carac diff --git a/module/roll/roll-constants.mjs b/module/roll/roll-constants.mjs index d99d3760..d9733e0c 100644 --- a/module/roll/roll-constants.mjs +++ b/module/roll/roll-constants.mjs @@ -1,5 +1,6 @@ export const ROLL_TYPE_ATTAQUE = 'attaque' +export const ROLL_TYPE_POSSESSION = 'possession' export const ROLL_TYPE_COMP = 'comp' export const ROLL_TYPE_CUISINE = 'cuisine' export const ROLL_TYPE_DEFENSE = 'defense' @@ -27,8 +28,8 @@ export const DIFF = { export const DIFFS = { [DIFF.LIBRE]: { key: DIFF.LIBRE, label: "Difficulté libre", libre: true, visible: true, max: 0 }, [DIFF.ATTAQUE]: { key: DIFF.ATTAQUE, label: "Difficulté d'attaque", libre: true, visible: true, max: 0 }, - [DIFF.IMPOSEE]: { key: DIFF.IMPOSEE, label: "Diffficulté imposée", libre: false, visible: true, max: 0 }, - [DIFF.DEFENSE]: { key: DIFF.DEFENSE, label: "Diffficulté défense", libre: false, visible: true, max: 0 }, + [DIFF.IMPOSEE]: { key: DIFF.IMPOSEE, label: "Difficulté imposée", libre: false, visible: true, max: 0 }, + [DIFF.DEFENSE]: { key: DIFF.DEFENSE, label: "Difficulté défense", libre: false, visible: true, max: 0 }, [DIFF.DEFAUT]: { key: DIFF.DEFAUT, label: "Difficulté", libre: true, visible: true, max: 5 }, [DIFF.AUCUN]: { key: DIFF.AUCUN, label: "", libre: false, visible: false, max: 0 }, } diff --git a/module/roll/roll-type-possession.mjs b/module/roll/roll-type-possession.mjs new file mode 100644 index 00000000..81ba089c --- /dev/null +++ b/module/roll/roll-type-possession.mjs @@ -0,0 +1,33 @@ +import { DIFF, ROLL_TYPE_POSSESSION } from "./roll-constants.mjs" +import { RollType } from "./roll-type.mjs" + + +export const TYPE_POSSESSION = { + POSSEDER: 'posseder', + CONJURER: 'conjurer', + DEFENSE: 'defense' +} +export class RollTypePossession extends RollType { + get code() { return ROLL_TYPE_POSSESSION } + get name() { return `Posséder` } + + title(rollData) { + const isEntite = this.isEntite(rollData) + if (this.isDefense(rollData)) { + return `résiste à la ${isEntite ? 'conjuration' : 'possession'}` + } + return `tente de ${isEntite ? 'posséder' : 'conjurer'}` + } + + onSelect(rollData) { + this.setDiffType(rollData, this.isDefense(rollData) ? DIFF.DEFENSE : DIFF.ATTAQUE) + } + + isEntite(rollData) { + return rollData.active.actor.isEntiteNonIncarnee() + } + + isDefense(rollData) { + return rollData.type.possession == TYPE_POSSESSION.DEFENSE + } +} \ No newline at end of file From fd3f988a4f88ec2224df75c46dc959d8bb0bcfd2 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 28 Nov 2025 19:44:06 +0100 Subject: [PATCH 02/17] Roll V2 mode possession --- module/actor/base-actor-sang.js | 1 - module/rdd-roll-encaisser.js | 2 +- module/roll/roll-dialog.mjs | 4 ++ module/roll/roll-part-possession.mjs | 79 +++++++++++++++++++++++ module/roll/roll-type-possession.mjs | 2 +- templates/roll/result/chat-possession.hbs | 22 +++++++ templates/roll/roll-part-possession.hbs | 7 ++ 7 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 module/roll/roll-part-possession.mjs create mode 100644 templates/roll/result/chat-possession.hbs create mode 100644 templates/roll/roll-part-possession.hbs diff --git a/module/actor/base-actor-sang.js b/module/actor/base-actor-sang.js index 07922963..74bcc4f5 100644 --- a/module/actor/base-actor-sang.js +++ b/module/actor/base-actor-sang.js @@ -7,7 +7,6 @@ import { RdDDice } from "../rdd-dice.js"; import { RdDItemBlessure } from "../item/blessure.js"; import { ChatUtility } from "../chat-utility.js"; import { Misc } from "../misc.js"; -import { CARACS } from "../rdd-carac.js"; /** * Classe de base pour les acteurs qui peuvent subir des blessures diff --git a/module/rdd-roll-encaisser.js b/module/rdd-roll-encaisser.js index 813b1266..b24c65d4 100644 --- a/module/rdd-roll-encaisser.js +++ b/module/rdd-roll-encaisser.js @@ -16,7 +16,7 @@ export class RdDEncaisser extends Dialog { /* -------------------------------------------- */ constructor(html, actor) { - if (actor.isEntiteNonIncarnee([ENTITE_NONINCARNE])) { + if (actor.isEntiteNonIncarnee()) { throw `${actor.name} est une entité non incarnée et ne peut pas subnir de dommages` } diff --git a/module/roll/roll-dialog.mjs b/module/roll/roll-dialog.mjs index b179bb9e..d5863d87 100644 --- a/module/roll/roll-dialog.mjs +++ b/module/roll/roll-dialog.mjs @@ -48,6 +48,8 @@ import { RollPartEmpoignade } from "./roll-part-empoignade.mjs"; import { RollPartEmpoignadeTaille } from "./roll-part-empoignade-taille.mjs"; import { RollPartEcailles } from "./roll-part-ecailles.mjs"; import { RollPartResistance } from "./roll-part-resistance.mjs"; +import { RollTypePossession } from "./roll-type-possession.mjs"; +import { RollPartPossession } from "./roll-part-possession.mjs"; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api @@ -56,6 +58,7 @@ export const ALL_ROLL_TYPES = [ new RollTypeComp(), new RollTypeTache(), new RollTypeAttaque(), + new RollTypePossession(), new RollTypeDefense(), new RollTypeSort(), new RollTypeMeditation(), @@ -76,6 +79,7 @@ const ROLL_PARTS = [ new RollPartDiff(), new RollPartAttaque(), + new RollPartPossession(), new RollPartDefense(), new RollPartMeditation(), new RollPartSort(), diff --git a/module/roll/roll-part-possession.mjs b/module/roll/roll-part-possession.mjs new file mode 100644 index 00000000..b33a7ab5 --- /dev/null +++ b/module/roll/roll-part-possession.mjs @@ -0,0 +1,79 @@ +import { CATEGORIES_COMPETENCES_CREATURES } from "../item/base-items.js" +import { CARACS } from "../rdd-carac.js" +import { ROLL_TYPE_POSSESSION } from "./roll-constants.mjs" +import { PART_CARAC } from "./roll-part-carac.mjs" +import { PART_COMP } from "./roll-part-comp.mjs" +import { RollPartSelect } from "./roll-part-select.mjs" +import { ROLLDIALOG_SECTION } from "./roll-part.mjs" + +export const PART_POSSESSION = "possession" + +export class RollPartPossession extends RollPartSelect { + + /** TODO: remplacer selectOption par un sélecteur plus sympa (avec image de compétence, par exemple? */ + + get code() { return PART_POSSESSION } + get name() { return 'Possession' } + get section() { return ROLLDIALOG_SECTION.CHOIX } + + visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_POSSESSION) } + + loadRefs(rollData) { + const refs = this.getRefs(rollData) + const selected = this.getSelected(rollData) + refs.all = this.$getActorConjurations(rollData) + refs.isPersonnage = rollData.active.actor.isPersonnage() + refs.isENI = rollData.active.actor.isEntiteNonIncarnee() + + this.$selectPossession(rollData) + } + + choices(refs) { return refs.all } + + $getActorConjurations(rollData) { + const competences = rollData.active.actor.getDraconicOuPossession() + return competences.map(RollPartPossession.extractPossession) + } + + static extractPossession(comp) { + return { + key: comp.id ?? comp.name, + label: `${comp.system.categorie == CATEGORIES_COMPETENCES_CREATURES.possession.key ? 'Possession': 'Conjuration'} (${comp.name})`, + value: comp.system.niveau, + comp: comp + } + } + + prepareContext(rollData) { + this.$selectPossession(rollData) + } + getAjustements(rollData) { + return [] + } + async _onRender(rollDialog, context, options) { + const select = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-possession"]`) + + select?.addEventListener("change", e => { + const selectOptions = e.currentTarget.options + const index = selectOptions.selectedIndex + this.$selectPossession(rollDialog.rollData, selectOptions[index]?.value) + rollDialog.render() + }) + } + + $selectPossession(rollData, key) { + this.selectByKey(rollData, key, 0) + } + + impactOtherPart(part, rollData) { + if (this.visible(rollData)) { + const current = this.getCurrent(rollData) + switch (part.code) { + case PART_CARAC: return part.filterCaracs(rollData, [this.getRefs(rollData).isPersonnage ? CARACS.REVE_ACTUEL : CARACS.REVE]) + case PART_COMP: return part.filterComps(rollData, [current.comp?.name]) + } + } + return undefined + } + +} diff --git a/module/roll/roll-type-possession.mjs b/module/roll/roll-type-possession.mjs index 81ba089c..64f1a64a 100644 --- a/module/roll/roll-type-possession.mjs +++ b/module/roll/roll-type-possession.mjs @@ -14,7 +14,7 @@ export class RollTypePossession extends RollType { title(rollData) { const isEntite = this.isEntite(rollData) if (this.isDefense(rollData)) { - return `résiste à la ${isEntite ? 'conjuration' : 'possession'}` + return `résiste à la ${isEntite ? 'conjuration' : 'possession'} de` } return `tente de ${isEntite ? 'posséder' : 'conjurer'}` } diff --git a/templates/roll/result/chat-possession.hbs b/templates/roll/result/chat-possession.hbs new file mode 100644 index 00000000..44377d02 --- /dev/null +++ b/templates/roll/result/chat-possession.hbs @@ -0,0 +1,22 @@ +
+
+ + +
+
+ {{active.name}} possession {{opponent.name}}: {{current}} +
+ +
+ {{> 'partial-infojet'}} +
+ +
+
+ +
+
+ +
+
+
diff --git a/templates/roll/roll-part-possession.hbs b/templates/roll/roll-part-possession.hbs new file mode 100644 index 00000000..62ac46f8 --- /dev/null +++ b/templates/roll/roll-part-possession.hbs @@ -0,0 +1,7 @@ + + + + + From 706aa657b1457c4d9a43d6ec7436588cffae5125 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Mon, 1 Dec 2025 00:51:44 +0100 Subject: [PATCH 03/17] =?UTF-8?q?M=C3=A9thode=20rollPossession=20pour=20at?= =?UTF-8?q?taque=20possession?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ajout d'une méthode pour ouvrir le dialogue en mode possession - gestion des information de possession - fenêtre défense possession - préparation des messages de tchat --- module/actor/base-actor-reve.js | 24 +++- module/rdd-possession-v2.mjs | 132 ++++++++++++++++++ module/rdd-possession.js | 21 +-- module/roll/chat-roll-result.mjs | 17 ++- module/roll/roll-dialog.mjs | 5 +- module/roll/roll-part-possession.mjs | 24 ++-- module/roll/roll-type-possession.mjs | 25 ++-- module/roll/roll-type.mjs | 1 + template.json | 6 +- templates/chat-demande-defense-possession.hbs | 39 ++++++ ...on.hbs => chat-resultat-possession-v1.hbs} | 0 templates/item/possession-sheet.hbs | 1 - templates/roll/result/chat-possession.hbs | 8 +- templates/roll/roll-dialog.hbs | 2 +- templates/roll/roll-part-possession.hbs | 20 ++- 15 files changed, 270 insertions(+), 55 deletions(-) create mode 100644 module/rdd-possession-v2.mjs create mode 100644 templates/chat-demande-defense-possession.hbs rename templates/{chat-resultat-possession.hbs => chat-resultat-possession-v1.hbs} (100%) diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index b9a50ff4..84c70c78 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -26,11 +26,12 @@ import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, CATEGORIES_COMPETENCES_CREATURES } fr import { RollDataAjustements } from "../rolldata-ajustements-v1.js"; import { MappingCreatureArme } from "../item/mapping-creature-arme.mjs"; import RollDialog from "../roll/roll-dialog.mjs"; -import { ATTAQUE_ROLL_TYPES, DEFAULT_ROLL_TYPES, DIFF, DIFFS, ROLL_TYPE_ATTAQUE, ROLL_TYPE_COMP, ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_OEUVRE, ROLL_TYPE_TACHE } from "../roll/roll-constants.mjs"; +import { ATTAQUE_ROLL_TYPES, DEFAULT_ROLL_TYPES, DIFF, DIFFS, ROLL_TYPE_ATTAQUE, ROLL_TYPE_COMP, ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_OEUVRE, ROLL_TYPE_POSSESSION, ROLL_TYPE_TACHE } from "../roll/roll-constants.mjs"; import { OptionsAvancees, ROLL_DIALOG_V2 } from "../settings/options-avancees.js"; import { PART_COMP } from "../roll/roll-part-comp.mjs"; import { RdDInitiative } from "../initiative.mjs"; import { RdDItemCompetenceCreature } from "../item-competencecreature.js"; +import { ACTIONS_POSSESSION, RdDPossessionV2 } from "../rdd-possession-v2.mjs"; /** * Classe de base pour les acteurs disposant de rêve (donc, pas des objets) @@ -598,6 +599,27 @@ export class RdDBaseActorReve extends RdDBaseActor { }) } + rollPossession() { + Targets.selectOneTargetToken(async target => { + const selectedToken = RdDUtility.getSelectedToken(this) + RollDialog.create( + { + ids: { + actorId: this.id, + actorTokenId: selectedToken.id, + opponentId: target.actor.id, + opponentTokenId: target.id + }, + type: { allowed: [ROLL_TYPE_POSSESSION], current: ROLL_TYPE_POSSESSION, possession: { action: ACTIONS_POSSESSION.ATTAQUE } }, + passeArme: foundry.utils.randomID(16), + }, + { + onRollDone: RollDialog.onRollDoneClose, + callbacks: [async (roll) => await RdDPossessionV2.chatMessageDefensePossession(roll)] + }) + }) + } + verifierForceMin(item) { } /* -------------------------------------------- */ diff --git a/module/rdd-possession-v2.mjs b/module/rdd-possession-v2.mjs new file mode 100644 index 00000000..7c2da7bc --- /dev/null +++ b/module/rdd-possession-v2.mjs @@ -0,0 +1,132 @@ +import { ITEM_TYPES, RDD_CONFIG } from "./constants.js"; +import { RdDRollResult } from "./rdd-roll-result.js"; +import { RollBasicParts } from "./roll/roll-basic-parts.mjs"; +import { ChatUtility } from "./chat-utility.js"; +import RollDialog from "./roll/roll-dialog.mjs"; + +export const ACTIONS_POSSESSION = { + ATTAQUE: 'attaque', + POSSEDER: 'posseder', + CONJURER: 'conjurer', + DEFENSE: 'defense', + DEFENSE_POSSESSION: 'defense-possession', + DEFENSE_CONJURATION: 'defense-conjuration' +} + +export class RdDPossessionV2 { + + static init() { + } + + static $isInverse(entite, victime) { + return !entite.isEntiteNonIncarnee() && victime.isEntiteNonIncarnee() + } + + /* -------------------------------------------- */ + static findPossession(entite, victime) { + if (RdDPossessionV2.$isInverse(entite, victime)) { + return RdDPossessionV2.findPossession(victime, entite) + } + return victime.itemTypes[ITEM_TYPES.possession].find(poss => poss.system.entiteid == entite.id) + } + + static async createPossession(entite, victime) { + if (RdDPossessionV2.$isInverse(entite, victime)) { + return await RdDPossessionV2.createPossession(victime, entite) + } + const existing = RdDPossessionV2.findPossession(entite, victime) + if (!existing) { + await victime.createEmbeddedDocuments('Item', [{ + name: `Possession de ${entite.name}`, + type: ITEM_TYPES.possession, + img: RDD_CONFIG.icons.possession, + system: { entiteid: entite.id, victimeid: victime.id, compteur: 0 } + }]) + } + } + + static getPossessionDetails(rollData, action) { + const isEntite = rollData.active.actor.isEntiteNonIncarnee() && !rollData.opponent.actor.isEntiteNonIncarnee() + const itemPossession = RdDPossessionV2.findPossession(rollData.active.actor, rollData.opponent.actor) + const compteur = itemPossession?.system.compteur ?? 0 + const isAttaque = RdDPossessionV2.isAttaque(action) + action = RdDPossessionV2.$getAction(isAttaque, isEntite) + + return { + action: action, + isEntite: isEntite, + isAttaque: isAttaque, + isPersonnage: rollData.active.actor.isPersonnage(), + isCompteurPossession: Math.sign(compteur) >= 0, + compteur: Math.abs(compteur) + } + } + + static $getAction(isAttaque, isEntite) { + if (isAttaque) { + return isEntite ? ACTIONS_POSSESSION.POSSEDER : ACTIONS_POSSESSION.CONJURER + } + return isEntite ? ACTIONS_POSSESSION.DEFENSE_CONJURATION : ACTIONS_POSSESSION.DEFENSE_POSSESSION + } + + static actionTitle(action) { + switch (action) { + case ACTIONS_POSSESSION.POSSEDER: return "tente de posséder" + case ACTIONS_POSSESSION.CONJURER: return "tente de conjurer" + case ACTIONS_POSSESSION.DEFENSE_POSSESSION: return "résiste à la possession de" + case ACTIONS_POSSESSION.DEFENSE_CONJURATION: return "résiste à la conjuration de" + case ACTIONS_POSSESSION.DEFENSE: return "résiste à " + } + return "lutte contre" + } + + static isAttaque(action) { + return ![ACTIONS_POSSESSION.DEFENSE, ACTIONS_POSSESSION.DEFENSE_POSSESSION, ACTIONS_POSSESSION.DEFENSE_CONJURATION].includes(action) + } + + static async addPointPossession(entite, victime, add) { + if (RdDPossessionV2.$isInverse(entite, victime)) { + return await RdDPossessionV2.addPointPossession(victime, entite, /* negate?*/ add) + } + const existing = RdDPossessionV2.findPossession(entite, victime) + if (!existing) { + return + } + const points = add ? 1 : -1 + const compteur = (existing.system.compteur ?? 0) + points + await victime.updateEmbeddedDocuments('Item', [{ id: existing.id, 'system.compteur': compteur }]) + } + + static callbacksOnDefensePossession() { + return [async roll => { + + }] + } + + static async chatMessageDefensePossession(attackerRoll) { + + const defense = RollBasicParts.prepareDefense(attackerRoll) + defense.type = { + possession: RdDPossessionV2.getPossessionDetails(defense, ACTIONS_POSSESSION.DEFENSE) + } + + const chatDemandeDefense = await ChatMessage.create({ + // message privé: du défenseur à lui même (et aux GMs) + speaker: ChatMessage.getSpeaker({ actor: defense.active.actor, token: defense.active.token }), + alias: attackerRoll.active.name, + whisper: ChatUtility.getOwners(defense.active.actor), + content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense-possession.hbs', defense) + }); + ChatUtility.setMessageData(chatDemandeDefense, 'demande-defense', true) + // // flag pour garder les jets d'attaque/defense + ChatUtility.setMessageData(chatDemandeDefense, 'rollData', { + ids: defense.ids, + attackerRoll: RollDialog.saveParts(attackerRoll), + passeArme: defense.passeArme + }) + } + + static async chatMarquerPointPossession(roll) { + } + +} \ No newline at end of file diff --git a/module/rdd-possession.js b/module/rdd-possession.js index c8cade05..dab70705 100644 --- a/module/rdd-possession.js +++ b/module/rdd-possession.js @@ -18,9 +18,9 @@ export class RdDPossession { /* -------------------------------------------- */ static searchPossessionFromEntite(attacker, defender) { - let poss = attacker.items.find(poss => poss.type == ITEM_TYPES.possession && poss.system.victime.actorid == defender.id); + let poss = attacker.itemTypes[ITEM_TYPES.possession].find(poss => poss.system.victime.actorid == defender.id); if (!poss) { - poss = defender.items.find(poss => poss.type == ITEM_TYPES.possession && poss.system.victime.actorid == defender.id); + poss = defender.itemTypes[ITEM_TYPES.possession].find(poss => poss.system.victime.actorid == defender.id); } return poss && foundry.utils.duplicate(poss) || undefined; } @@ -132,7 +132,7 @@ export class RdDPossession { } const possession = (rollData.isECNIDefender ? rollData.attacker : rollData.defender).getPossession(rollData.possession.system.possessionid) RdDPossession.storePossessionAttaque(possession, rollData) - await RdDRollResult.displayRollData(rollData, rollData.defender, 'chat-resultat-possession.hbs'); + await RdDRollResult.displayRollData(rollData, rollData.defender, 'chat-resultat-possession-v1.hbs'); } /* -------------------------------------------- */ @@ -172,7 +172,7 @@ export class RdDPossession { rollData.possession = possession RdDPossession.$updateEtatPossession(rollData.possession) - await RdDRollResult.displayRollData(rollData, rollData.attacker, 'chat-resultat-possession.hbs') + await RdDRollResult.displayRollData(rollData, rollData.attacker, 'chat-resultat-possession-v1.hbs') if (rollData.possession.isPosseder || rollData.possession.isConjurer) { // conjuration await victime.deleteEmbeddedDocuments("Item", [rollData.possession._id]) @@ -226,15 +226,18 @@ export class RdDPossession { /* -------------------------------------------- */ static async createPossession(attacker, defender) { return await Item.create({ - name: "Possession en cours de " + attacker.name, type: 'possession', - img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp", + name: `Possession de ${entite.name}`, + type: ITEM_TYPES.possession, + img: RDD_CONFIG.icons.possession, system: { - description: "", typepossession: attacker.name, + typepossession: attacker.name, possede: false, possessionid: foundry.utils.randomID(16), + entiteid: attacker.id, + victimeid: defender.id, + compteur: 0, entite: { actorid: attacker.id }, - victime: { actorid: defender.id }, - compteur: 0 + victime: { actorid: defender.id } } }, { diff --git a/module/roll/chat-roll-result.mjs b/module/roll/chat-roll-result.mjs index 4e892d6b..d55eab81 100644 --- a/module/roll/chat-roll-result.mjs +++ b/module/roll/chat-roll-result.mjs @@ -53,19 +53,19 @@ export default class ChatRollResult { prepareDisplay(roll) { roll.done = roll.done ?? {} roll.show = roll.show ?? {} - roll.show.chance = this.isAppelChancePossible(roll) - roll.show.encaissement = this.isShowEncaissement(roll) - roll.show.recul = this.getRecul(roll) - roll.show.maladresse = this.getMaladresse(roll) + roll.show.chance = this.$isAppelChancePossible(roll) + roll.show.encaissement = this.$isShowEncaissement(roll) + roll.show.recul = this.$getRecul(roll) + roll.show.maladresse = this.$getMaladresse(roll) } - isAppelChancePossible(roll) { + $isAppelChancePossible(roll) { return roll.active.actor.isPersonnage() && roll.rolled.isEchec && RdDCarac.isActionPhysique(roll.current.carac?.key) } - isShowEncaissement(roll) { + $isShowEncaissement(roll) { switch (roll.type.current) { case ROLL_TYPE_DEFENSE: return roll.rolled.isEchec @@ -73,7 +73,7 @@ export default class ChatRollResult { return false } - getMaladresse(roll) { + $getMaladresse(roll) { switch (roll.type.current) { case ROLL_TYPE_DEFENSE: if (roll.rolled.isETotal) { @@ -91,7 +91,7 @@ export default class ChatRollResult { return undefined } - getRecul(roll, defender = roll.active.actor, attacker = roll.opponent?.actor) { + $getRecul(roll, defender = roll.active.actor, attacker = roll.opponent?.actor) { switch (roll.type.current) { case ROLL_TYPE_DEFENSE: { @@ -195,7 +195,6 @@ export default class ChatRollResult { this.getCombat(reRoll)?.doRollDefense(reRoll, callbacks) break case ROLL_TYPE_ATTAQUE: - // TODO this.getCombat(reRoll)?.doRollAttaque(reRoll, callbacks) break default: { diff --git a/module/roll/roll-dialog.mjs b/module/roll/roll-dialog.mjs index d5863d87..7787212c 100644 --- a/module/roll/roll-dialog.mjs +++ b/module/roll/roll-dialog.mjs @@ -370,10 +370,11 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 selectType() { - const selectedType = this.getSelectedType(); - this.rollData.type.label = selectedType.title(this.rollData) + const selectedType = this.getSelectedType() + selectedType.prepare(this.rollData) selectedType.setRollDataType(this.rollData) selectedType.onSelect(this.rollData) + this.rollData.type.label = selectedType.title(this.rollData) ROLL_PARTS.find(it => it.code == PART_CARAC).filterCaracs(this.rollData) ROLL_PARTS.find(it => it.code == PART_COMP).filterComps(this.rollData) diff --git a/module/roll/roll-part-possession.mjs b/module/roll/roll-part-possession.mjs index b33a7ab5..7a0f857c 100644 --- a/module/roll/roll-part-possession.mjs +++ b/module/roll/roll-part-possession.mjs @@ -1,5 +1,6 @@ import { CATEGORIES_COMPETENCES_CREATURES } from "../item/base-items.js" import { CARACS } from "../rdd-carac.js" +import { RdDPossessionV2 } from "../rdd-possession-v2.mjs" import { ROLL_TYPE_POSSESSION } from "./roll-constants.mjs" import { PART_CARAC } from "./roll-part-carac.mjs" import { PART_COMP } from "./roll-part-comp.mjs" @@ -20,14 +21,11 @@ export class RollPartPossession extends RollPartSelect { loadRefs(rollData) { const refs = this.getRefs(rollData) - const selected = this.getSelected(rollData) refs.all = this.$getActorConjurations(rollData) - refs.isPersonnage = rollData.active.actor.isPersonnage() - refs.isENI = rollData.active.actor.isEntiteNonIncarnee() - this.$selectPossession(rollData) } + choices(refs) { return refs.all } $getActorConjurations(rollData) { @@ -38,7 +36,7 @@ export class RollPartPossession extends RollPartSelect { static extractPossession(comp) { return { key: comp.id ?? comp.name, - label: `${comp.system.categorie == CATEGORIES_COMPETENCES_CREATURES.possession.key ? 'Possession': 'Conjuration'} (${comp.name})`, + label: `${comp.system.categorie == CATEGORIES_COMPETENCES_CREATURES.possession.key ? 'Possession' : 'Conjuration'} (${comp.name})`, value: comp.system.niveau, comp: comp } @@ -47,18 +45,26 @@ export class RollPartPossession extends RollPartSelect { prepareContext(rollData) { this.$selectPossession(rollData) } + getAjustements(rollData) { return [] } - async _onRender(rollDialog, context, options) { - const select = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-possession"]`) + async _onRender(rollDialog, context, options) { + const rollData = rollDialog.rollData + const select = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-possession"]`) + const button = rollDialog.element.querySelector(`roll-section[name="${this.code}"] button[name="creer-possession"]`) select?.addEventListener("change", e => { const selectOptions = e.currentTarget.options const index = selectOptions.selectedIndex - this.$selectPossession(rollDialog.rollData, selectOptions[index]?.value) + this.$selectPossession(rollData, selectOptions[index]?.value) rollDialog.render() }) + button?.addEventListener("click", async e => { + e.preventDefault() + await RdDPossessionV2.createPossession(rollData.active.actor, rollData.opponent.actor) + rollDialog.render() + }) } $selectPossession(rollData, key) { @@ -69,7 +75,7 @@ export class RollPartPossession extends RollPartSelect { if (this.visible(rollData)) { const current = this.getCurrent(rollData) switch (part.code) { - case PART_CARAC: return part.filterCaracs(rollData, [this.getRefs(rollData).isPersonnage ? CARACS.REVE_ACTUEL : CARACS.REVE]) + case PART_CARAC: return part.filterCaracs(rollData, [rollData.type.possession.isPersonnage ? CARACS.REVE_ACTUEL : CARACS.REVE]) case PART_COMP: return part.filterComps(rollData, [current.comp?.name]) } } diff --git a/module/roll/roll-type-possession.mjs b/module/roll/roll-type-possession.mjs index 64f1a64a..b9438a74 100644 --- a/module/roll/roll-type-possession.mjs +++ b/module/roll/roll-type-possession.mjs @@ -1,33 +1,28 @@ +import { RdDPossessionV2 } from "../rdd-possession-v2.mjs" import { DIFF, ROLL_TYPE_POSSESSION } from "./roll-constants.mjs" import { RollType } from "./roll-type.mjs" - -export const TYPE_POSSESSION = { - POSSEDER: 'posseder', - CONJURER: 'conjurer', - DEFENSE: 'defense' -} export class RollTypePossession extends RollType { get code() { return ROLL_TYPE_POSSESSION } - get name() { return `Posséder` } + get name() { return "Posséder" } + + prepare(rollData) { + rollData.type.possession = RdDPossessionV2.getPossessionDetails(rollData, rollData.type.possession?.action) + } title(rollData) { - const isEntite = this.isEntite(rollData) - if (this.isDefense(rollData)) { - return `résiste à la ${isEntite ? 'conjuration' : 'possession'} de` - } - return `tente de ${isEntite ? 'posséder' : 'conjurer'}` + return RdDPossessionV2.actionTitle(rollData.type.possession.action) } onSelect(rollData) { - this.setDiffType(rollData, this.isDefense(rollData) ? DIFF.DEFENSE : DIFF.ATTAQUE) + this.setDiffType(rollData, this.isAttaque(rollData) ? DIFF.ATTAQUE : DIFF.DEFENSE) } isEntite(rollData) { return rollData.active.actor.isEntiteNonIncarnee() } - isDefense(rollData) { - return rollData.type.possession == TYPE_POSSESSION.DEFENSE + isAttaque(rollData) { + return RdDPossessionV2.isAttaque(rollData.type.possession.action) } } \ No newline at end of file diff --git a/module/roll/roll-type.mjs b/module/roll/roll-type.mjs index 193ae420..44b85035 100644 --- a/module/roll/roll-type.mjs +++ b/module/roll/roll-type.mjs @@ -16,6 +16,7 @@ export class RollType { return { code: this.code, name: this.name, icon: this.icon, section: 'type', template: this.template, selected: this.isSelected(rollData) } } + prepare(rollData){} isAllowed(rollData) { return rollData.type.allowed == undefined || rollData.type.allowed.includes(this.code) } visible(rollData) { return true } title(rollData) { return this.code } diff --git a/template.json b/template.json index 7fbff462..b35d9e21 100644 --- a/template.json +++ b/template.json @@ -648,10 +648,11 @@ "immobilise": false }, "possession": { - "templates": ["description"], "typepossession": "", "possede": false, "possessionid": "", + "entiteid": "", + "compteur": 0, "entite": { "actorid": "", "diffLibre": 0, @@ -661,8 +662,7 @@ "actorid": "", "diffLibre": 0, "finesse": false - }, - "compteur": 0 + } }, "blessure": { "templates": ["temporel"], diff --git a/templates/chat-demande-defense-possession.hbs b/templates/chat-demande-defense-possession.hbs new file mode 100644 index 00000000..a15baa9e --- /dev/null +++ b/templates/chat-demande-defense-possession.hbs @@ -0,0 +1,39 @@ +
+
+ +
+ +
+

Défense de {{active.name}}

+
+ +
+ {{log 'chat-resultat-possession' this}} + {{#if type.possession.isEntite}} + {{!-- {{#if (eq mode "attaque")}} + {{attacker.name}} tente de {{#if isECNIDefender}}conjurer la possession de{{else}}posséder{{/if}} {{defender.name}} + {{else}} + {{defender.name}} tente de {{#if isECNIDefender}}résister à{{else}}conjurer la possession de{{/if}} {{attacker.name}} + {{/if}} --}} + {{/if}} +

Points de {{#if type.possession.isCompteurPossession}}possession{{else}}conjuration{{/if}}: {{type.possession.compteur}}

+
+ +
+
+ + +
diff --git a/templates/chat-resultat-possession.hbs b/templates/chat-resultat-possession-v1.hbs similarity index 100% rename from templates/chat-resultat-possession.hbs rename to templates/chat-resultat-possession-v1.hbs diff --git a/templates/item/possession-sheet.hbs b/templates/item/possession-sheet.hbs index ffdea2e8..dfff8092 100644 --- a/templates/item/possession-sheet.hbs +++ b/templates/item/possession-sheet.hbs @@ -14,6 +14,5 @@ - {{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.hbs"}} diff --git a/templates/roll/result/chat-possession.hbs b/templates/roll/result/chat-possession.hbs index 44377d02..35de8780 100644 --- a/templates/roll/result/chat-possession.hbs +++ b/templates/roll/result/chat-possession.hbs @@ -1,10 +1,11 @@ +{{log 'roll-chat-possession' this}}
- {{active.name}} possession {{opponent.name}}: {{current}} + {{active.name}} {{type.label}} {{opponent.name}}
@@ -15,6 +16,11 @@
+ {{#if roll.type.possession.isAttaque}} + proposer defense + {{else}} + proposer marquer points + {{/if}}
diff --git a/templates/roll/roll-dialog.hbs b/templates/roll/roll-dialog.hbs index 748460bc..54714a20 100644 --- a/templates/roll/roll-dialog.hbs +++ b/templates/roll/roll-dialog.hbs @@ -12,4 +12,4 @@ {{#each templates as |template|}}{{> 'roll-section' rollData=@root.rollData currentsection='ajustements'}}{{/each}} {{> 'roll-button' }} - + \ No newline at end of file diff --git a/templates/roll/roll-part-possession.hbs b/templates/roll/roll-part-possession.hbs index 62ac46f8..49f83080 100644 --- a/templates/roll/roll-part-possession.hbs +++ b/templates/roll/roll-part-possession.hbs @@ -1,7 +1,19 @@ + + + + - - + + + +

Points de {{#if rollData.type.possession.isCompteurPossession}}possession{{else}}conjuration{{/if}}: {{rollData.type.possession.compteur}}

+
+ + + + +
From 19cabe816ea2d68cd4a304555e4cb6cd4b09d236 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Tue, 2 Dec 2025 23:58:17 +0100 Subject: [PATCH 04/17] =?UTF-8?q?Gestion=20d=C3=A9fense=20et=20compteur=20?= =?UTF-8?q?de=20possession?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/actor/base-actor-reve.js | 19 +-- module/chat-utility.js | 9 ++ module/rdd-combat.js | 6 +- module/rdd-empoignade.js | 6 +- module/rdd-possession-v2.mjs | 138 ++++++++++++++---- module/rdd-utility.js | 5 +- module/roll/chat-roll-result.mjs | 26 +++- module/roll/roll-basic-parts.mjs | 10 +- module/roll/roll-dialog.mjs | 37 +++-- module/roll/roll-part-defense.mjs | 4 +- module/roll/roll-part-possession.mjs | 2 +- module/roll/roll-part-sign.mjs | 20 ++- module/roll/roll-type-possession.mjs | 2 +- templates/chat-demande-defense-possession.hbs | 39 ----- templates/chat-demande-defense.hbs | 9 +- templates/possession/chat-demande-defense.hbs | 36 +++++ templates/possession/chat-message-marquer.hbs | 24 +++ templates/roll/result/chat-possession.hbs | 27 +++- 18 files changed, 282 insertions(+), 137 deletions(-) delete mode 100644 templates/chat-demande-defense-possession.hbs create mode 100644 templates/possession/chat-demande-defense.hbs create mode 100644 templates/possession/chat-message-marquer.hbs diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index 84c70c78..b5d60cd6 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -600,24 +600,7 @@ export class RdDBaseActorReve extends RdDBaseActor { } rollPossession() { - Targets.selectOneTargetToken(async target => { - const selectedToken = RdDUtility.getSelectedToken(this) - RollDialog.create( - { - ids: { - actorId: this.id, - actorTokenId: selectedToken.id, - opponentId: target.actor.id, - opponentTokenId: target.id - }, - type: { allowed: [ROLL_TYPE_POSSESSION], current: ROLL_TYPE_POSSESSION, possession: { action: ACTIONS_POSSESSION.ATTAQUE } }, - passeArme: foundry.utils.randomID(16), - }, - { - onRollDone: RollDialog.onRollDoneClose, - callbacks: [async (roll) => await RdDPossessionV2.chatMessageDefensePossession(roll)] - }) - }) + RdDPossessionV2.rollAttaquePossession(this) } verifierForceMin(item) { } diff --git a/module/chat-utility.js b/module/chat-utility.js index bd3e97c8..da97495d 100644 --- a/module/chat-utility.js +++ b/module/chat-utility.js @@ -76,6 +76,15 @@ export class ChatUtility { ChatUtility.removeMessages({ part: part }); } + static remover(chatMessage) { + const messageId = chatMessage.id; + if (messageId) { + return (..._) => ChatUtility.removeMessages({ messageId: messageId }); + + } + return (..._) => { } + } + static removeChatMessageId(messageId) { if (messageId) { ChatUtility.removeMessages({ messageId: messageId }); diff --git a/module/rdd-combat.js b/module/rdd-combat.js index b2294b56..80e85b56 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -369,8 +369,7 @@ export class RdDCombat { } static rddCombatForAttackV2(attackerRoll) { - const defenderRoll = RollBasicParts.prepareDefense(attackerRoll) - return RdDCombat.rddCombatForDefenseV2(defenderRoll) + return RdDCombat.rddCombatForDefenseV2(RollBasicParts.prepareDefense(attackerRoll)) } static rddCombatForDefenseV2(defenderRoll) { @@ -755,7 +754,7 @@ export class RdDCombat { } async _chatMessageDefenseV2(paramDemandeDefense) { - const attackerRoll = paramDemandeDefense.attackerRoll; + const attackerRoll = paramDemandeDefense.attackerRoll RollBasicParts.loadSurprises(attackerRoll) attackerRoll.dmg = RdDBonus.dmgRollV2(attackerRoll, attackerRoll.current.attaque) @@ -1086,7 +1085,6 @@ export class RdDCombat { async defenseV2(attackerRoll, callbacks = []) { // this._prepareParade(attackerRoll, arme, competence); - RollDialog.loadRollData(attackerRoll) await this.doRollDefense({ ids: { actorId: this.defender.id, diff --git a/module/rdd-empoignade.js b/module/rdd-empoignade.js index 70482a8c..d8109a7a 100644 --- a/module/rdd-empoignade.js +++ b/module/rdd-empoignade.js @@ -89,20 +89,20 @@ export class RdDEmpoignade { const chatMessage = ChatUtility.getChatMessage(event); const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage); RdDEmpoignade.entrainerAuSol(rollData) - ChatUtility.removeChatMessageId(chatMessage.id) + ChatUtility.remover(chatMessage)() }); $(html).on("click", '.empoignade-projeter-sol', event => { const chatMessage = ChatUtility.getChatMessage(event); const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage); RdDEmpoignade.projeterAuSol(rollData) - ChatUtility.removeChatMessageId(chatMessage.id) + ChatUtility.remover(chatMessage)() }); $(html).on("change", '.empoignade-perte-endurance', event => { const chatMessage = ChatUtility.getChatMessage(event); const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage); if (event.currentTarget.value && event.currentTarget.value != "none") { RdDEmpoignade.perteEndurance(rollData, event.currentTarget.value) - //ChatUtility.removeChatMessageId(chatMessage.id) + ChatUtility.remover(chatMessage)() } }); } diff --git a/module/rdd-possession-v2.mjs b/module/rdd-possession-v2.mjs index 7c2da7bc..3dd35be7 100644 --- a/module/rdd-possession-v2.mjs +++ b/module/rdd-possession-v2.mjs @@ -1,8 +1,10 @@ import { ITEM_TYPES, RDD_CONFIG } from "./constants.js"; -import { RdDRollResult } from "./rdd-roll-result.js"; import { RollBasicParts } from "./roll/roll-basic-parts.mjs"; import { ChatUtility } from "./chat-utility.js"; import RollDialog from "./roll/roll-dialog.mjs"; +import { Targets } from "./targets.js"; +import { RdDUtility } from "./rdd-utility.js"; +import { ROLL_TYPE_POSSESSION } from "./roll/roll-constants.mjs"; export const ACTIONS_POSSESSION = { ATTAQUE: 'attaque', @@ -30,9 +32,9 @@ export class RdDPossessionV2 { return victime.itemTypes[ITEM_TYPES.possession].find(poss => poss.system.entiteid == entite.id) } - static async createPossession(entite, victime) { + static async createPossessionIfMissing(entite, victime) { if (RdDPossessionV2.$isInverse(entite, victime)) { - return await RdDPossessionV2.createPossession(victime, entite) + return await RdDPossessionV2.createPossessionIfMissing(victime, entite) } const existing = RdDPossessionV2.findPossession(entite, victime) if (!existing) { @@ -45,21 +47,24 @@ export class RdDPossessionV2 { } } - static getPossessionDetails(rollData, action) { - const isEntite = rollData.active.actor.isEntiteNonIncarnee() && !rollData.opponent.actor.isEntiteNonIncarnee() - const itemPossession = RdDPossessionV2.findPossession(rollData.active.actor, rollData.opponent.actor) - const compteur = itemPossession?.system.compteur ?? 0 - const isAttaque = RdDPossessionV2.isAttaque(action) - action = RdDPossessionV2.$getAction(isAttaque, isEntite) + static getTypePossession(activeActor, opponentActor) { + const isEntite = activeActor.isEntiteNonIncarnee() && !opponentActor.isEntiteNonIncarnee(); + const itemPossession = RdDPossessionV2.findPossession(activeActor, opponentActor); + const compteur = itemPossession?.system.compteur ?? 0; return { - action: action, isEntite: isEntite, - isAttaque: isAttaque, - isPersonnage: rollData.active.actor.isPersonnage(), + isPersonnage: activeActor.isPersonnage(), isCompteurPossession: Math.sign(compteur) >= 0, compteur: Math.abs(compteur) - } + }; + } + + static getTypePossessionAction(roll, action) { + const possession = RdDPossessionV2.getTypePossession(roll.active.actor, roll.opponent.actor) + possession.isAttaque = RdDPossessionV2.isAttaque(action) + possession.action = RdDPossessionV2.$getAction(possession.isAttaque, possession.isEntite) + return possession } static $getAction(isAttaque, isEntite) { @@ -80,34 +85,106 @@ export class RdDPossessionV2 { return "lutte contre" } + static isDefense(action) { + return [ACTIONS_POSSESSION.DEFENSE, ACTIONS_POSSESSION.DEFENSE_POSSESSION, ACTIONS_POSSESSION.DEFENSE_CONJURATION].includes(action) + } static isAttaque(action) { - return ![ACTIONS_POSSESSION.DEFENSE, ACTIONS_POSSESSION.DEFENSE_POSSESSION, ACTIONS_POSSESSION.DEFENSE_CONJURATION].includes(action) + return [ACTIONS_POSSESSION.ATTAQUE, ACTIONS_POSSESSION.POSSEDER, ACTIONS_POSSESSION.CONJURER].includes(action) } - static async addPointPossession(entite, victime, add) { + static async rollAttaquePossession(actor) { + Targets.selectOneTargetToken(async target => { + const selectedToken = RdDUtility.getSelectedToken(actor) + RollDialog.create( + { + ids: { + actorId: actor.id, + actorTokenId: selectedToken.id, + opponentId: target.actor.id, + opponentTokenId: target.id + }, + passeArme: foundry.utils.randomID(16), + type: { allowed: [ROLL_TYPE_POSSESSION], current: ROLL_TYPE_POSSESSION, possession: { action: ACTIONS_POSSESSION.ATTAQUE } }, + }, + { + onRollDone: RollDialog.onRollDoneClose, + callbacks: [ + async (roll) => await RdDPossessionV2.createPossessionIfMissing(roll.active.actor, roll.opponent.actor), + async (roll) => RdDPossessionV2.$setParticuliereFinesse(roll), + async (roll) => await RdDPossessionV2.chatMessageDefensePossession(roll) + ] + }) + }) + } + + static $setParticuliereFinesse(roll) { + if (roll.rolled.isPart) { + roll.particuliere = RDD_CONFIG.particuliere.finesse.key + } + } + + static async rollDefensePossession(savedRoll, chatMessage) { + RollBasicParts.restore(savedRoll) + const attackerRoll = savedRoll.attackerRoll + RollDialog.create( + { + ids: savedRoll.ids, + passeArme: attackerRoll.passeArme, + type: { allowed: [ROLL_TYPE_POSSESSION], current: ROLL_TYPE_POSSESSION, possession: { action: ACTIONS_POSSESSION.DEFENSE } }, + selected: { diff: { value: attackerRoll.selected?.diff?.value ?? 0 } }, + attackerRoll: attackerRoll + }, + { + onRollDone: RollDialog.onRollDoneClose, callbacks: [ + async roll => await RdDPossessionV2.onRollDefense(roll), + ChatUtility.remover(chatMessage) + ] + }); + } + + static async onRollDefense(defense) { + if (defense.rolled.isEchec) { + await RdDPossessionV2.addPointPossession(defense.opponent.actor, defense.active.actor) + } + RdDPossessionV2.resetPossession(defense) + } + + static async onMarquerPointPossession(roll) { + roll.type = {} + await RdDPossessionV2.addPointPossession(roll.opponent.actor, roll.active.actor) + RdDPossessionV2.resetPossession(roll) + + await ChatMessage.create({ + // message privé: du défenseur à lui même (et aux GMs) + speaker: ChatMessage.getSpeaker({ actor: roll.active.actor, token: roll.active.token }), + alias: roll.opponent.name, + whisper: ChatUtility.getOwners(roll.active.actor), + content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/possession/chat-message-marquer.hbs`, roll) + }) + } + + static resetPossession(roll) { + roll.type.possession = foundry.utils.mergeObject( + roll.type.possession ?? {}, + RdDPossessionV2.getTypePossession(roll.opponent.actor, roll.active.actor)) + } + + static async addPointPossession(entite, victime, points = 1) { if (RdDPossessionV2.$isInverse(entite, victime)) { - return await RdDPossessionV2.addPointPossession(victime, entite, /* negate?*/ add) + return await RdDPossessionV2.addPointPossession(victime, entite, - points) } const existing = RdDPossessionV2.findPossession(entite, victime) - if (!existing) { - return + if (existing) { + const compteur = (existing.system.compteur ?? 0) + points + await victime.updateEmbeddedDocuments('Item', [{ _id: existing.id, 'system.compteur': compteur }]) } - const points = add ? 1 : -1 - const compteur = (existing.system.compteur ?? 0) + points - await victime.updateEmbeddedDocuments('Item', [{ id: existing.id, 'system.compteur': compteur }]) - } - - static callbacksOnDefensePossession() { - return [async roll => { - - }] } static async chatMessageDefensePossession(attackerRoll) { const defense = RollBasicParts.prepareDefense(attackerRoll) defense.type = { - possession: RdDPossessionV2.getPossessionDetails(defense, ACTIONS_POSSESSION.DEFENSE) + possession: RdDPossessionV2.getTypePossessionAction(defense, ACTIONS_POSSESSION.DEFENSE) } const chatDemandeDefense = await ChatMessage.create({ @@ -115,7 +192,7 @@ export class RdDPossessionV2 { speaker: ChatMessage.getSpeaker({ actor: defense.active.actor, token: defense.active.token }), alias: attackerRoll.active.name, whisper: ChatUtility.getOwners(defense.active.actor), - content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense-possession.hbs', defense) + content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/possession/chat-demande-defense.hbs', defense) }); ChatUtility.setMessageData(chatDemandeDefense, 'demande-defense', true) // // flag pour garder les jets d'attaque/defense @@ -126,7 +203,4 @@ export class RdDPossessionV2 { }) } - static async chatMarquerPointPossession(roll) { - } - } \ No newline at end of file diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 4ffd88ff..fa2085a0 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -776,8 +776,9 @@ export class RdDUtility { let sommeAPayer = Number(event.currentTarget.attributes['data-somme-a-payer']?.value ?? 0); let actor = RdDUtility.getSelectedActor("Pour effectuer le paiement:"); if (actor) { - actor.payerSols(sommeAPayer); - ChatUtility.removeChatMessageId(RdDUtility.findChatMessageId(event.currentTarget)); + actor.payerSols(sommeAPayer) + const chatMessage = RdDUtility.findChatMessageId(event.currentTarget) + ChatUtility.remover(chatMessage)() } }); $(html).on("click", '.rdd-world-content-link', async event => { diff --git a/module/roll/chat-roll-result.mjs b/module/roll/chat-roll-result.mjs index d55eab81..036b2f7a 100644 --- a/module/roll/chat-roll-result.mjs +++ b/module/roll/chat-roll-result.mjs @@ -13,6 +13,8 @@ import { PART_ATTAQUE } from "./roll-part-attaque.mjs" import { RdDRollTables } from "../rdd-rolltables.js" import { RdDEmpoignade } from "../rdd-empoignade.js" import { Misc } from "../misc.js" +import { RollBasicParts } from "./roll-basic-parts.mjs" +import { RdDPossessionV2 } from "../rdd-possession-v2.mjs" export default class ChatRollResult { static init() { @@ -134,6 +136,8 @@ export default class ChatRollResult { $(html).on("click", '.appel-chance', event => this.onClickAppelChance(event)) $(html).on("click", '.appel-destinee', event => this.onClickAppelDestinee(event)) $(html).on("click", '.button-defense', event => this.onClickDefense(event)) + $(html).on("click", '.button-defense-possession', event => this.onClickDefensePossession(event)) + $(html).on("click", '.marquer-point-possession', event => this.onClickMarquerPointPossession(event)) $(html).on("click", '.encaissement', event => this.onClickEncaissement(event)) $(html).on("click", '.resister-recul', event => this.onClickRecul(event)) $(html).on("click", '.choix-particuliere', event => this.onClickChoixParticuliere(event)) @@ -187,7 +191,7 @@ export default class ChatRollResult { console.log('onAppelChanceSuccess savedRoll', savedRoll) reRoll.type.retry = true await this.updateChatMessage(chatMessage, reRoll) - const callbacks = [r => ChatUtility.removeChatMessageId(chatMessage.id)] + const callbacks = [ChatUtility.remover(chatMessage)] // TODO: annuler les effets switch (reRoll.type.current) { @@ -226,12 +230,28 @@ export default class ChatRollResult { async onClickDefense(event) { const chatMessage = ChatUtility.getChatMessage(event) const savedRoll = this.loadChatMessageRoll(chatMessage) + RollBasicParts.restore(savedRoll) const attackerRoll = savedRoll.attackerRoll + RollDialog.loadRollData(attackerRoll) this.getCombat(attackerRoll)?.defenseV2(attackerRoll, - [roll => { ChatUtility.removeChatMessageId(chatMessage.id) }] + [ChatUtility.remover(chatMessage)] ) } + async onClickDefensePossession(event) { + const chatMessage = ChatUtility.getChatMessage(event) + const savedRoll = this.loadChatMessageRoll(chatMessage) + await RdDPossessionV2.rollDefensePossession(savedRoll, chatMessage) + } + + async onClickMarquerPointPossession(event) { + const chatMessage = ChatUtility.getChatMessage(event) + const savedRoll = this.loadChatMessageRoll(chatMessage) + RollBasicParts.restore(savedRoll) + await RdDPossessionV2.onMarquerPointPossession(savedRoll) + ChatUtility.remover(chatMessage)() + } + async onClickEncaissement(event) { const chatMessage = ChatUtility.getChatMessage(event) const isMessageDemande = ChatUtility.getMessageData(chatMessage, 'demande-defense') @@ -254,7 +274,7 @@ export default class ChatRollResult { break } if (isMessageDemande) { - ChatUtility.removeChatMessageId(chatMessage.id) + ChatUtility.remover(chatMessage)() } else { savedRoll.done.encaissement = true await this.updateChatMessage(chatMessage, savedRoll) diff --git a/module/roll/roll-basic-parts.mjs b/module/roll/roll-basic-parts.mjs index d8c9c51b..981a6f78 100644 --- a/module/roll/roll-basic-parts.mjs +++ b/module/roll/roll-basic-parts.mjs @@ -11,7 +11,7 @@ export class RollBasicParts { rollData.ids.sceneId = rollData.ids.sceneId ?? canvas.scene.id rollData.active = RollBasicParts.getTokenActor(rollData) rollData.opponent = RollBasicParts.getTokenActorOpponent(rollData) - if (rollData.type.opposed == undefined) { + if (rollData.type && rollData.type.opposed == undefined) { rollData.type.opposed = rollData.opponent != null } } @@ -46,10 +46,10 @@ export class RollBasicParts { type: rollData.type, ids: { sceneId: rollData.ids.sceneId, - actorId: rollData.active.id, - actorTokenId: rollData.active.tokenId, - opponentId: isOpposed ? rollData.opponent.id : undefined, - opponentTokenId: isOpposed ? rollData.opponent.tokenId : undefined, + actorId: rollData.ids.actorId, + actorTokenId: rollData.ids.actorTokenId, + opponentId: isOpposed ? rollData.ids.opponentId : undefined, + opponentTokenId: isOpposed ? rollData.ids.opponentTokenId : undefined, } } } diff --git a/module/roll/roll-dialog.mjs b/module/roll/roll-dialog.mjs index 7787212c..601cc79e 100644 --- a/module/roll/roll-dialog.mjs +++ b/module/roll/roll-dialog.mjs @@ -318,15 +318,33 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 return rollData } - static saveParts(rollData, impacts) { + static saveParts(rollData, impacts = undefined) { + if (rollData == undefined) { + return undefined + } + + function saveBasics(from, to) { + if (from) { + to.passeArme = from.passeArme + to.rolled = from.rolled + to.particuliere = from.particuliere + to.result = from.result + to.done = from.done ?? {} + to.dmg = from.dmg + if (from.attackerRoll) { + to.attackerRoll = {} + saveBasics(from.attackerRoll, to.attackerRoll) + } + } + } + const target = RollBasicParts.initFrom(rollData) - ROLL_PARTS.filter(p => p.isActive(rollData)) - .forEach(p => p.storeClean(rollData, target)) - target.attackerRoll = rollData.attackerRoll - target.rolled = rollData.rolled - target.result = rollData.result - target.done = rollData.done ?? {} - target.dmg = rollData.dmg + if (rollData.current) { + // stockage de current + ROLL_PARTS.filter(p => p.isActive(rollData)) + .forEach(p => p.storeClean(rollData, target)) + } + saveBasics(rollData, target) if (impacts) { target.reverse = { active: impacts.active?.reverseImpacts(), @@ -334,6 +352,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 } } return target + } constructor(rollData, rollOptions) { @@ -352,7 +371,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 } this.chatRollResult = new ChatRollResult() this.selectType() - this.registerHooks(rollData); + this.registerHooks(rollData) } registerHooks(rollData) { diff --git a/module/roll/roll-part-defense.mjs b/module/roll/roll-part-defense.mjs index d89935d6..ab13927e 100644 --- a/module/roll/roll-part-defense.mjs +++ b/module/roll/roll-part-defense.mjs @@ -16,8 +16,8 @@ export class RollPartDefense extends RollPartSelect { get code() { return PART_DEFENSE } get section() { return ROLLDIALOG_SECTION.CHOIX } - isValid(rollData) { return rollData.attackerRoll != undefined } - visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_DEFENSE) } + isValid(rollData) { return this.isRollType(rollData, ROLL_TYPE_DEFENSE) && rollData.attackerRoll != undefined } + visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_DEFENSE) && rollData.attackerRoll != undefined } static getDiffAttaque(attackerRoll) { // TODO: rollDataV2? diff --git a/module/roll/roll-part-possession.mjs b/module/roll/roll-part-possession.mjs index 7a0f857c..0cec1ab8 100644 --- a/module/roll/roll-part-possession.mjs +++ b/module/roll/roll-part-possession.mjs @@ -62,7 +62,7 @@ export class RollPartPossession extends RollPartSelect { }) button?.addEventListener("click", async e => { e.preventDefault() - await RdDPossessionV2.createPossession(rollData.active.actor, rollData.opponent.actor) + await RdDPossessionV2.createPossessionIfMissing(rollData.active.actor, rollData.opponent.actor) rollDialog.render() }) } diff --git a/module/roll/roll-part-sign.mjs b/module/roll/roll-part-sign.mjs index 3fd26a2d..d3a5a3c3 100644 --- a/module/roll/roll-part-sign.mjs +++ b/module/roll/roll-part-sign.mjs @@ -1,8 +1,9 @@ import { RDD_CONFIG } from "../constants.js" import { Misc } from "../misc.js" +import { RdDPossessionV2 } from "../rdd-possession-v2.mjs" import { ReglesOptionnelles } from "../settings/regles-optionnelles.js" -import { demiReveStatusEffect, StatusEffects } from "../settings/status-effects.js" -import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs" +import { StatusEffects } from "../settings/status-effects.js" +import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE, ROLL_TYPE_POSSESSION } from "./roll-constants.mjs" import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" export const PART_SIGN = "sign" @@ -25,7 +26,7 @@ export class RollPartSign extends RollPart { } isCombat(rollData) { - return [ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE].includes(rollData.type.current) || rollData.type.isCombat + return [ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE, ROLL_TYPE_POSSESSION].includes(rollData.type.current) } prepareContext(rollData) { @@ -40,7 +41,7 @@ export class RollPartSign extends RollPart { const isCombat = this.isCombat(rollData) const current = this.getCurrent(rollData) current.armeDisparate = isCombat && current.armeDisparate - current.surprise = actor.getSurprise(isCombat, current.forceRequise ?? 0) + current.surprise = actor.getSurprise(isCombat, current.forceRequise ?? 0) current.reasons = actor.getEffects(it => StatusEffects.niveauSurprise(it, isCombat) > 0, current.forceRequise ?? 0) .map(it => { return { img: it.img, label: game.i18n.localize(it.name) } }) current.diviseur = 1 @@ -67,7 +68,16 @@ export class RollPartSign extends RollPart { } isAttaqueFinesse(rollData) { - return ROLL_TYPE_DEFENSE == rollData.type.current && rollData.attaque?.particuliere == 'finesse' + const attackerRoll = rollData.attackerRoll + if (rollData.attackerRoll){ + switch (rollData.type.current) { + case ROLL_TYPE_DEFENSE: + return attackerRoll?.particuliere == RDD_CONFIG.particuliere.finesse.key + case ROLL_TYPE_POSSESSION: + return RdDPossessionV2.isDefense(rollData.type.possession.action) && attackerRoll?.particuliere == RDD_CONFIG.particuliere.finesse.key + } + } + return false } isParadeArmeDisparate(current) { diff --git a/module/roll/roll-type-possession.mjs b/module/roll/roll-type-possession.mjs index b9438a74..8082c690 100644 --- a/module/roll/roll-type-possession.mjs +++ b/module/roll/roll-type-possession.mjs @@ -7,7 +7,7 @@ export class RollTypePossession extends RollType { get name() { return "Posséder" } prepare(rollData) { - rollData.type.possession = RdDPossessionV2.getPossessionDetails(rollData, rollData.type.possession?.action) + rollData.type.possession = RdDPossessionV2.getTypePossessionAction(rollData, rollData.type.possession?.action) } title(rollData) { diff --git a/templates/chat-demande-defense-possession.hbs b/templates/chat-demande-defense-possession.hbs deleted file mode 100644 index a15baa9e..00000000 --- a/templates/chat-demande-defense-possession.hbs +++ /dev/null @@ -1,39 +0,0 @@ -
-
- -
- -
-

Défense de {{active.name}}

-
- -
- {{log 'chat-resultat-possession' this}} - {{#if type.possession.isEntite}} - {{!-- {{#if (eq mode "attaque")}} - {{attacker.name}} tente de {{#if isECNIDefender}}conjurer la possession de{{else}}posséder{{/if}} {{defender.name}} - {{else}} - {{defender.name}} tente de {{#if isECNIDefender}}résister à{{else}}conjurer la possession de{{/if}} {{attacker.name}} - {{/if}} --}} - {{/if}} -

Points de {{#if type.possession.isCompteurPossession}}possession{{else}}conjuration{{/if}}: {{type.possession.compteur}}

-
- -
-
- - -
diff --git a/templates/chat-demande-defense.hbs b/templates/chat-demande-defense.hbs index 6825a003..28ef4eb6 100644 --- a/templates/chat-demande-defense.hbs +++ b/templates/chat-demande-defense.hbs @@ -28,13 +28,8 @@
{{#unless (eq active.surprise.key 'totale')}} - - + + Se défendre {{#if (or (eq attackerRoll.attaqueCategorie 'tir') (eq attackerRoll.attaqueCategorie 'lancer'))}} (difficulté à déterminer) diff --git a/templates/possession/chat-demande-defense.hbs b/templates/possession/chat-demande-defense.hbs new file mode 100644 index 00000000..3c94d1c7 --- /dev/null +++ b/templates/possession/chat-demande-defense.hbs @@ -0,0 +1,36 @@ + diff --git a/templates/possession/chat-message-marquer.hbs b/templates/possession/chat-message-marquer.hbs new file mode 100644 index 00000000..9a8c2839 --- /dev/null +++ b/templates/possession/chat-message-marquer.hbs @@ -0,0 +1,24 @@ +
+
+ + +
+ +
+

Pas de défense de {{active.name}}

+
+ +
+

Un point de {{#if type.possession.isEntite}}conjuration{{else}}possession{{/if}} a été ajouté.

+

+ Points de {{#if type.possession.isCompteurPossession}}possession{{else}}conjuration{{/if}} + actuels: {{type.possession.compteur}} +

+
+ +
+
+ +
+
+
diff --git a/templates/roll/result/chat-possession.hbs b/templates/roll/result/chat-possession.hbs index 35de8780..ce170775 100644 --- a/templates/roll/result/chat-possession.hbs +++ b/templates/roll/result/chat-possession.hbs @@ -1,4 +1,4 @@ -{{log 'roll-chat-possession' this}} +{{log 'chat-possession' this}}
@@ -13,14 +13,29 @@
+

+ {{#if rolled.isSuccess}} + {{#if type.possession.isAttaque}} + La tentative a réussi, l'adversaire peut tenter de contrer. + {{else}} + La tentative de contre a réussi, pas de changements des points de {{#if type.possession.isCompteurPossession}}possession{{else}}conjuration{{/if}}. + {{/if}} + {{else}} + {{#if type.possession.isAttaque}} + La tentative a échoué, pas de changements des points de {{#if type.possession.isCompteurPossession}}possession{{else}}conjuration{{/if}}. + {{else}} + La tentative de contre a échoué. Les points de {{#if type.possession.isCompteurPossession}}possession{{else}}conjuration{{/if}} + sont ajustés. + {{/if}} + {{/if}} +

+

+ Points de {{#if type.possession.isCompteurPossession}}possession{{else}}conjuration{{/if}} + actuels: {{type.possession.compteur}} +

- {{#if roll.type.possession.isAttaque}} - proposer defense - {{else}} - proposer marquer points - {{/if}}
From 98e8c7a10c6a9c626a9b3b057d4f1116e83fb710 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 5 Dec 2025 18:03:08 +0100 Subject: [PATCH 05/17] Gestion de possession - fin de round MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - affichage du message pour indiquer l'état d'une possession en fin de round - bouton de conjuration depuis la feuille de personnage --- module/actor.js | 8 +- module/actor/base-actor-reve.js | 23 ++-- module/rdd-possession-v2.mjs | 107 ++++++++++++++----- module/roll/roll-part-possession.mjs | 2 +- module/roll/roll-type-possession.mjs | 2 +- template.json | 3 + templates/actor/possessions.hbs | 7 +- templates/possession/chat-fin-possession.hbs | 16 +++ 8 files changed, 127 insertions(+), 41 deletions(-) create mode 100644 templates/possession/chat-fin-possession.hbs diff --git a/module/actor.js b/module/actor.js index 21bd525e..a536f06d 100644 --- a/module/actor.js +++ b/module/actor.js @@ -52,6 +52,7 @@ import { PART_TACHE } from "./roll/roll-part-tache.mjs"; import { PART_COMP } from "./roll/roll-part-comp.mjs"; import { PART_OEUVRE } from "./roll/roll-part-oeuvre.mjs"; import { PART_CUISINE } from "./roll/roll-part-cuisine.mjs"; +import { RdDPossessionV2 } from "./rdd-possession-v2.mjs"; export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre'] @@ -2567,7 +2568,12 @@ export class RdDActor extends RdDBaseActorSang { /* -------------------------------------------- */ conjurerPossession(possession) { - RdDPossession.onConjurerPossession(this, possession) + if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) { + RdDPossessionV2.rollConjurerPossession(this, possession) + } + else { + RdDPossession.onConjurerPossession(this, possession) + } } /* -------------------------------------------- */ diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index b5d60cd6..1f044431 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -176,13 +176,14 @@ export class RdDBaseActorReve extends RdDBaseActor { async santeIncDec(name, inc, isCritique = false) { } async finDeRound(options = { terminer: false }) { - await this.$finDeRoundSuppressionEffetsTermines(options); - await this.finDeRoundBlessures(); - await this.$finDeRoundSupprimerObsoletes(); - await this.$finDeRoundEmpoignade(); + await this.finDeRoundSuppressionEffetsTermines(options) + await this.finDeRoundBlessures() + await this.finDeRoundSupprimerObsoletes() + await this.finDeRoundEmpoignade() + await this.finDeRoundPossession() } - async $finDeRoundSuppressionEffetsTermines(options) { + async finDeRoundSuppressionEffetsTermines(options) { for (let effect of this.getEffects()) { if (effect.duration.type !== 'none' && (effect.duration.remaining <= 0 || options.terminer)) { await effect.delete(); @@ -194,20 +195,24 @@ export class RdDBaseActorReve extends RdDBaseActor { async finDeRoundBlessures() { } - async $finDeRoundSupprimerObsoletes() { + async finDeRoundSupprimerObsoletes() { const obsoletes = [] .concat(this.itemTypes[ITEM_TYPES.empoignade].filter(it => it.system.pointsemp <= 0)) - .concat(this.itemTypes[ITEM_TYPES.possession].filter(it => it.system.compteur < -2 || it.system.compteur > 2)) - .map(it => it.id); + .map(it => it.id) await this.deleteEmbeddedDocuments('Item', obsoletes); } - async $finDeRoundEmpoignade() { + async finDeRoundEmpoignade() { await Promise.all(this.itemTypes[ITEM_TYPES.empoignade] .filter(it => it.system.pointsemp >= 2 && it.system.empoigneurid == this.id) .map(async it => await RdDEmpoignade.onImmobilisation(this, it))) } + async finDeRoundPossession(){ + await Promise.all(this.itemTypes[ITEM_TYPES.possession] + .map(async it => await RdDPossessionV2.onPossession(this, it))) + } + async setSonne(sonne = true) { } /* -------------------------------------------- */ diff --git a/module/rdd-possession-v2.mjs b/module/rdd-possession-v2.mjs index 3dd35be7..b1594dad 100644 --- a/module/rdd-possession-v2.mjs +++ b/module/rdd-possession-v2.mjs @@ -5,6 +5,7 @@ import RollDialog from "./roll/roll-dialog.mjs"; import { Targets } from "./targets.js"; import { RdDUtility } from "./rdd-utility.js"; import { ROLL_TYPE_POSSESSION } from "./roll/roll-constants.mjs"; +import { TokenActor } from "./technical/actor-token.mjs"; export const ACTIONS_POSSESSION = { ATTAQUE: 'attaque', @@ -21,7 +22,7 @@ export class RdDPossessionV2 { } static $isInverse(entite, victime) { - return !entite.isEntiteNonIncarnee() && victime.isEntiteNonIncarnee() + return !entite.actor.isEntiteNonIncarnee() && victime.actor.isEntiteNonIncarnee() } /* -------------------------------------------- */ @@ -29,7 +30,7 @@ export class RdDPossessionV2 { if (RdDPossessionV2.$isInverse(entite, victime)) { return RdDPossessionV2.findPossession(victime, entite) } - return victime.itemTypes[ITEM_TYPES.possession].find(poss => poss.system.entiteid == entite.id) + return victime.actor.itemTypes[ITEM_TYPES.possession].find(it => it.system.entiteid == entite.id) } static async createPossessionIfMissing(entite, victime) { @@ -38,30 +39,36 @@ export class RdDPossessionV2 { } const existing = RdDPossessionV2.findPossession(entite, victime) if (!existing) { - await victime.createEmbeddedDocuments('Item', [{ + await victime.actor.createEmbeddedDocuments('Item', [{ name: `Possession de ${entite.name}`, type: ITEM_TYPES.possession, img: RDD_CONFIG.icons.possession, - system: { entiteid: entite.id, victimeid: victime.id, compteur: 0 } + system: { + entiteid: entite.actor.id, + entitetokenid: entite.token.id, + victimeid: victime.actor.id, + victimetokenid: victime.token.id, + compteur: 0 + } }]) } } - static getTypePossession(activeActor, opponentActor) { - const isEntite = activeActor.isEntiteNonIncarnee() && !opponentActor.isEntiteNonIncarnee(); - const itemPossession = RdDPossessionV2.findPossession(activeActor, opponentActor); - const compteur = itemPossession?.system.compteur ?? 0; + static getTypePossession(active, opponent) { + const itemPossession = RdDPossessionV2.findPossession(active, opponent) + const isEntite = active.actor.isEntiteNonIncarnee() && !opponent.actor.isEntiteNonIncarnee() + const compteur = itemPossession?.system.compteur ?? 0 return { isEntite: isEntite, - isPersonnage: activeActor.isPersonnage(), + isPersonnage: active.actor.isPersonnage(), isCompteurPossession: Math.sign(compteur) >= 0, compteur: Math.abs(compteur) - }; + } } - static getTypePossessionAction(roll, action) { - const possession = RdDPossessionV2.getTypePossession(roll.active.actor, roll.opponent.actor) + static getTypePossessionAction(active, opponent, action) { + const possession = RdDPossessionV2.getTypePossession(active, opponent) possession.isAttaque = RdDPossessionV2.isAttaque(action) possession.action = RdDPossessionV2.$getAction(possession.isAttaque, possession.isEntite) return possession @@ -93,8 +100,8 @@ export class RdDPossessionV2 { } static async rollAttaquePossession(actor) { + const selectedToken = RdDUtility.getSelectedToken(actor) Targets.selectOneTargetToken(async target => { - const selectedToken = RdDUtility.getSelectedToken(actor) RollDialog.create( { ids: { @@ -109,7 +116,7 @@ export class RdDPossessionV2 { { onRollDone: RollDialog.onRollDoneClose, callbacks: [ - async (roll) => await RdDPossessionV2.createPossessionIfMissing(roll.active.actor, roll.opponent.actor), + async (roll) => await RdDPossessionV2.createPossessionIfMissing(roll.active, roll.opponent), async (roll) => RdDPossessionV2.$setParticuliereFinesse(roll), async (roll) => await RdDPossessionV2.chatMessageDefensePossession(roll) ] @@ -117,6 +124,32 @@ export class RdDPossessionV2 { }) } + static async rollConjurerPossession(actor, possession) { + if (possession.system.possede){ + ui.notifications.warn(`${actor.name} est totalement possédé, impossible de conjurer l'entité`) + return + } + RollDialog.create( + { + ids: { + actorId: possession.system.victimeid, + actorTokenId: possession.system.victimetokenid, + opponentId: possession.system.entiteid, + opponentTokenId: possession.system.entitetokenid + }, + passeArme: foundry.utils.randomID(16), + type: { allowed: [ROLL_TYPE_POSSESSION], current: ROLL_TYPE_POSSESSION, possession: { action: ACTIONS_POSSESSION.ATTAQUE } }, + }, + { + onRollDone: RollDialog.onRollDoneClose, + callbacks: [ + async (roll) => await RdDPossessionV2.createPossessionIfMissing(roll.active, roll.opponent), + async (roll) => RdDPossessionV2.$setParticuliereFinesse(roll), + async (roll) => await RdDPossessionV2.chatMessageDefensePossession(roll) + ] + }) + } + static $setParticuliereFinesse(roll) { if (roll.rolled.isPart) { roll.particuliere = RDD_CONFIG.particuliere.finesse.key @@ -140,18 +173,20 @@ export class RdDPossessionV2 { ChatUtility.remover(chatMessage) ] }); - } - - static async onRollDefense(defense) { - if (defense.rolled.isEchec) { - await RdDPossessionV2.addPointPossession(defense.opponent.actor, defense.active.actor) - } - RdDPossessionV2.resetPossession(defense) } + + static async onRollDefense(defense) { + if (defense.rolled.isEchec) { + await RdDPossessionV2.addPointPossession(defense.opponent.actor, defense.active.actor) + } + RdDPossessionV2.resetPossession(defense) + } + + static async onMarquerPointPossession(roll) { roll.type = {} - await RdDPossessionV2.addPointPossession(roll.opponent.actor, roll.active.actor) + await RdDPossessionV2.addPointPossession(roll.opponent, roll.active) RdDPossessionV2.resetPossession(roll) await ChatMessage.create({ @@ -166,7 +201,7 @@ export class RdDPossessionV2 { static resetPossession(roll) { roll.type.possession = foundry.utils.mergeObject( roll.type.possession ?? {}, - RdDPossessionV2.getTypePossession(roll.opponent.actor, roll.active.actor)) + RdDPossessionV2.getTypePossession(roll.opponent, roll.active)) } static async addPointPossession(entite, victime, points = 1) { @@ -176,7 +211,7 @@ export class RdDPossessionV2 { const existing = RdDPossessionV2.findPossession(entite, victime) if (existing) { const compteur = (existing.system.compteur ?? 0) + points - await victime.updateEmbeddedDocuments('Item', [{ _id: existing.id, 'system.compteur': compteur }]) + await victime.actor.updateEmbeddedDocuments('Item', [{ _id: existing.id, 'system.compteur': compteur }]) } } @@ -184,7 +219,7 @@ export class RdDPossessionV2 { const defense = RollBasicParts.prepareDefense(attackerRoll) defense.type = { - possession: RdDPossessionV2.getTypePossessionAction(defense, ACTIONS_POSSESSION.DEFENSE) + possession: RdDPossessionV2.getTypePossessionAction(defense.active, defense.opponent, ACTIONS_POSSESSION.DEFENSE) } const chatDemandeDefense = await ChatMessage.create({ @@ -203,4 +238,24 @@ export class RdDPossessionV2 { }) } -} \ No newline at end of file + static async onPossession(actor, possession) { + if (Math.abs(possession.system.compteur) >= 2) { + await ChatMessage.create({ + alias: actor.getAlias(), + whisper: ChatUtility.getOwners(actor), + content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/possession/chat-fin-possession.hbs', { + possession, + active: TokenActor.fromActor(actor), + opponent: TokenActor.fromActor(game.actors.get(possession.system.entiteid)) + }) + }) + + if (possession.system.compteur <= -2) { + await actor.deleteEmbeddedDocuments('Item', [possession.id]) + } + if (possession.system.compteur >= 2) { + await actor.updateEmbeddedDocuments('Item', [{ _id: possession.id, 'system.possede': true }]) + } + } + } +} diff --git a/module/roll/roll-part-possession.mjs b/module/roll/roll-part-possession.mjs index 0cec1ab8..7e146ddd 100644 --- a/module/roll/roll-part-possession.mjs +++ b/module/roll/roll-part-possession.mjs @@ -62,7 +62,7 @@ export class RollPartPossession extends RollPartSelect { }) button?.addEventListener("click", async e => { e.preventDefault() - await RdDPossessionV2.createPossessionIfMissing(rollData.active.actor, rollData.opponent.actor) + await RdDPossessionV2.createPossessionIfMissing(rollData.active, rollData.opponent) rollDialog.render() }) } diff --git a/module/roll/roll-type-possession.mjs b/module/roll/roll-type-possession.mjs index 8082c690..305df461 100644 --- a/module/roll/roll-type-possession.mjs +++ b/module/roll/roll-type-possession.mjs @@ -7,7 +7,7 @@ export class RollTypePossession extends RollType { get name() { return "Posséder" } prepare(rollData) { - rollData.type.possession = RdDPossessionV2.getTypePossessionAction(rollData, rollData.type.possession?.action) + rollData.type.possession = RdDPossessionV2.getTypePossessionAction(rollData.active, rollData.opponent, rollData.type.possession?.action) } title(rollData) { diff --git a/template.json b/template.json index b35d9e21..7f9a96e7 100644 --- a/template.json +++ b/template.json @@ -652,6 +652,9 @@ "possede": false, "possessionid": "", "entiteid": "", + "entitetokenid": "", + "victimeid": "", + "victimetokenid": "", "compteur": 0, "entite": { "actorid": "", diff --git a/templates/actor/possessions.hbs b/templates/actor/possessions.hbs index 2d9ce67c..bf5caff6 100644 --- a/templates/actor/possessions.hbs +++ b/templates/actor/possessions.hbs @@ -4,14 +4,15 @@
  • Nom - Type
  • {{#each possessions as |possession key|}}
  • - {{possession.name}} (Conjurer) + {{possession.name}} + {{#unless possession.system.possede}} + Conjurer + {{/unless}} - {{possession.system.type}} {{>'systems/foundryvtt-reve-de-dragon/templates/actor/item-action-controls.hbs' item=possession options=@root.options}}
  • {{/each}} diff --git a/templates/possession/chat-fin-possession.hbs b/templates/possession/chat-fin-possession.hbs new file mode 100644 index 00000000..f9c78edd --- /dev/null +++ b/templates/possession/chat-fin-possession.hbs @@ -0,0 +1,16 @@ +
    +
    + + +
    + +
    +

    {{active.name}} + {{#if (gt possession.system.compteur 0)}}est maintenant possédé par{{else}}a conjuré{{/if}} + {{opponent.name}}

    +
    + +
    +
    + +
    From 05036877eda20747a5f00101c7b1732f7a66c68e Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 5 Dec 2025 19:24:48 +0100 Subject: [PATCH 06/17] Possessions dans HUD Permettre de commencer les possessions V2 --- changelog.md | 6 ++++++ module/actor/base-actor-reve.js | 4 ++-- module/actor/base-actor.js | 7 ++----- module/actor/entite.js | 13 +++++++++++-- module/item.js | 2 +- module/rdd-token-hud.js | 22 +++++++++++++++++----- templates/hud-actor-combat.hbs | 19 ++++++++----------- 7 files changed, 47 insertions(+), 26 deletions(-) diff --git a/changelog.md b/changelog.md index 2b22053e..1cdef3fe 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,11 @@ # 13.0 +## 13.0.21 - La folie d'Illysis + +- Fenêtre de jet v2 + - les possessions sont maintenant gérées avec les fenêtres V2 + - on peut choisir sa voie de draconic pour contrer une possession ou conjurer + ## 13.0.20 - L'immobilisme d'Illysis - Centrage du logo de pause diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index 1f044431..7515df40 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -121,7 +121,7 @@ export class RdDBaseActorReve extends RdDBaseActor { getDraconicOuPossession() { return [ ...this.getDraconics(), - ...this.itemTypes[ITEM_TYPES.competencecreature].filter(it => it.system.ispossession || it.system.categorie == CATEGORIES_COMPETENCES_CREATURES.possession.key), + ...this.itemTypes[ITEM_TYPES.competencecreature].filter(it => it.isCompetencePossession()), this.getConjurationNaturelle() ].sort(Misc.descending(it => it.system.niveau)); } @@ -164,7 +164,7 @@ export class RdDBaseActorReve extends RdDBaseActor { return this.itemTypes[ITEM_TYPES.competencecreature] .filter(it => it.isAttaque()) .map(it => it.attaqueCreature()) - .filter(it => it != undefined); + .filter(it => it != undefined) } async computeArmure(dmg) { return this.getProtectionNaturelle() } diff --git a/module/actor/base-actor.js b/module/actor/base-actor.js index 80cebd12..0308c88f 100644 --- a/module/actor/base-actor.js +++ b/module/actor/base-actor.js @@ -220,6 +220,7 @@ export class RdDBaseActor extends Actor { isEntite() { return false } isEntiteIncarnee() { return false } isEntiteNonIncarnee() { return false } + isEntiteBlurette() { return false } isHautRevant() { return false } isVehicule() { return false } isPersonnage() { return false } @@ -848,6 +849,7 @@ export class RdDBaseActor extends Actor { listActionsPossessions() { return this.itemTypes[ITEM_TYPES.possession] + .filter(it => !it.system.possede) .map(p => { return { label: p.name, @@ -856,9 +858,4 @@ export class RdDBaseActor extends Actor { } }) } - listActionsCombat() { - const possessions = this.listActionsPossessions() - return possessions.length > 0 ? possessions : this.listActions({}) - - } } \ No newline at end of file diff --git a/module/actor/entite.js b/module/actor/entite.js index a005fd28..21c2ad15 100644 --- a/module/actor/entite.js +++ b/module/actor/entite.js @@ -19,8 +19,8 @@ export class RdDEntite extends RdDBaseActorReve { isEntite() { return true } isEntiteNonIncarnee() { return this.system.definition.typeentite == ENTITE_NONINCARNE } - isEntiteIncarnee() { return [ENTITE_INCARNE, ENTITE_BLURETTE].includes(this.system.definition.typeentite) } - isEntiteBlurette() { return this.system.definition.typeentite !== ENTITE_BLURETTE } + isEntiteIncarnee() { return !this.isEntiteNonIncarnee() } + isEntiteBlurette() { return this.system.definition.typeentite == ENTITE_BLURETTE } getReveActuel() { return Misc.toInt(this.system.carac.reve?.value) @@ -101,6 +101,15 @@ export class RdDEntite extends RdDBaseActorReve { return true } + listActionsPossessions() { + if (this.isEntiteNonIncarnee()) { + return this.itemTypes[ITEM_TYPES.competencecreature] + .filter(it => it.system.ispossession) + .map(it => it.attaqueCreature()) + .filter(it => it != undefined) + } + return super.listActionsPossessions() + } /* -------------------------------------------- */ async setEntiteReveAccordee(actor) { if (this.isEntiteIncarnee()) { diff --git a/module/item.js b/module/item.js index a59e78ca..b9813d1d 100644 --- a/module/item.js +++ b/module/item.js @@ -205,7 +205,7 @@ export class RdDItem extends Item { return this.isCompetence() && ['melee', 'tir', 'lancer'].includes(this.system.categorie) } - isCompetencePossession() { return ITEM_TYPES.competencecreature == this.type && this.system.categorie == "possession" } + isCompetencePossession() { return ITEM_TYPES.competencecreature == this.type && this.system.categorie == CATEGORIES_COMPETENCES_CREATURES.possession.key } isTemporel() { return typesObjetsTemporels.includes(this.type) } isOeuvre() { return typesObjetsOeuvres.includes(this.type) } isDraconique() { return RdDItem.getItemTypesDraconiques().includes(this.type) } diff --git a/module/rdd-token-hud.js b/module/rdd-token-hud.js index f9612726..cbdc9e6c 100644 --- a/module/rdd-token-hud.js +++ b/module/rdd-token-hud.js @@ -34,7 +34,7 @@ export class RdDTokenHud { const actor = RdDCombatManager.getActorCombatant(combatant, { warning: false }) if (actor) { if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) { - await RdDTokenHud.addExtensionHudCombat(html, combatant, actor, token) + await RdDTokenHud.addExtensionHudCombatV2(html, combatant, actor, token) } else { const actions = RdDCombatManager.listActionsActorCombatant(actor) @@ -47,17 +47,28 @@ export class RdDTokenHud { } } - static async addExtensionHudCombat(html, combatant, actor, token) { - const actionsActor = actor.listActionsCombat(); + static async addExtensionHudCombatV2(html, combatant, actor, token) { + const isPossession = actor.listActionsPossessions().length > 0; + const actionsCombat = isPossession ? [] : actor.listAttaques() const ajustements = combatant?.initiative ? [ { label: 'Initiative +1', action: 'delta', value: 1 }, { label: 'Initiative -1', action: 'delta', value: -1 } ] : [] const autres = [{ label: "Autre action", action: 'autre' }] - const actions = Misc.indexed(actionsActor.concat(ajustements).concat(autres)) + const actions = Misc.indexed([ + ...actionsCombat, + ...ajustements, + ...autres + ]) - const hudData = { combatant, token, actions }; + const hudData = { + combatant, + token, + isPossession, + isEntiteNonIncarnee: actor.isEntiteNonIncarnee(), + actions, + }; const hud = $(await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/hud-actor-combat.hbs', hudData)) $(html).find('div.col.left').append(hud) @@ -84,6 +95,7 @@ export class RdDTokenHud { } }) list.find('.rdd-attaque-v2').click(event => combatant.actor.rollAttaque(token)) + list.find('.rdd-possession-v2').click(event => combatant.actor.rollPossession()) } static async addExtensionHudInit(html, combatant, actions) { diff --git a/templates/hud-actor-combat.hbs b/templates/hud-actor-combat.hbs index e3e921d4..c068e1ae 100644 --- a/templates/hud-actor-combat.hbs +++ b/templates/hud-actor-combat.hbs @@ -1,4 +1,3 @@ -{{log this}}
    - - {{!--
    - -
    --}} - + {{#if isPossession}} +
    + +
    + {{else}}
    + {{/if}}
From 46d09c7bd9f7ffc76454188114c7183bc4f1329f Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 5 Dec 2025 20:33:35 +0100 Subject: [PATCH 07/17] Dimension des zones editeur MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit amélioration des zones de saisie des éditeurs (journaux, ...) --- changelog.md | 1 + css/foundryvtt-reve-de-dragon.css | 18 ++++++++++++------ less/foundryvtt-reve-de-dragon.less | 26 ++++++++++++++++---------- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/changelog.md b/changelog.md index 1cdef3fe..02b4a6e2 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,7 @@ ## 13.0.21 - La folie d'Illysis +- La zone de saisie dans les journaux est mieux adaptée - Fenêtre de jet v2 - les possessions sont maintenant gérées avec les fenêtres V2 - on peut choisir sa voie de draconic pour contrer une possession ou conjurer diff --git a/css/foundryvtt-reve-de-dragon.css b/css/foundryvtt-reve-de-dragon.css index 1dba0a5e..eefcca81 100644 --- a/css/foundryvtt-reve-de-dragon.css +++ b/css/foundryvtt-reve-de-dragon.css @@ -1407,14 +1407,20 @@ select, } .system-foundryvtt-reve-de-dragon .app.sheet .editor.prosemirror { height: fit-content; - min-height: 5rem; + min-height: 6rem; } .system-foundryvtt-reve-de-dragon .app.sheet .editor.prosemirror .editor-container { - min-height: 5rem; - height: 8rem; + min-height: 6rem; + height: calc(100% - 3rem); margin: 0; flex: none; } +.system-foundryvtt-reve-de-dragon .app.sheet.journal-entry-page .editor.prosemirror { + height: 100%; +} +.system-foundryvtt-reve-de-dragon .app.sheet.journal-entry-page .editor.prosemirror .editor-container { + height: calc(100% - 6rem); +} .system-foundryvtt-reve-de-dragon .large-editor { border: 2; height: fit-content; @@ -1424,18 +1430,18 @@ select, .system-foundryvtt-reve-de-dragon .editor { border: 2; height: fit-content; - min-height: 5rem; + min-height: 6rem; padding: 0 3px; } .system-foundryvtt-reve-de-dragon .medium-editor { border: 2; - min-height: 8rem; + min-height: 9rem; padding: 0 3px; align-items: top; } .system-foundryvtt-reve-de-dragon .small-editor { border: 2; - min-height: 2rem; + min-height: 4rem; padding: 0 3px; } .system-foundryvtt-reve-de-dragon .foundryvtt-reve-de-dragon.sheet :is(.large-editor, .editor, .medium-editor, .small-editor) { diff --git a/less/foundryvtt-reve-de-dragon.less b/less/foundryvtt-reve-de-dragon.less index 9dabae69..4d59ed6f 100644 --- a/less/foundryvtt-reve-de-dragon.less +++ b/less/foundryvtt-reve-de-dragon.less @@ -719,14 +719,20 @@ } .app.sheet .editor.prosemirror { height: fit-content; - min-height: 5rem; - } - .app.sheet .editor.prosemirror .editor-container { - min-height: 5rem; - height: 8rem; - margin: 0; - flex: none; + min-height: 6rem; + .editor-container { + min-height: 6rem; + height: calc(100% - 3rem); + margin: 0; + flex: none; + } } + .app.sheet.journal-entry-page .editor.prosemirror{ + height: 100%; + .editor-container { + height: calc(100% - 6rem); + } + } .large-editor { border: 2; @@ -738,20 +744,20 @@ .editor { border: 2; height: fit-content; - min-height: 5rem; + min-height: 6rem; padding: 0 3px; } .medium-editor { border: 2; - min-height: 8rem; + min-height: 9rem; padding: 0 3px; align-items: top; } .small-editor { border: 2; - min-height: 2rem; + min-height: 4rem; padding: 0 3px; } From 90435c07b4ab675688e59d232f8fcc3b114953aa Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 6 Dec 2025 21:11:29 +0100 Subject: [PATCH 08/17] cleanup unused imports --- module/actor/base-actor-reve.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index 7515df40..cedfb66e 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -26,12 +26,12 @@ import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, CATEGORIES_COMPETENCES_CREATURES } fr import { RollDataAjustements } from "../rolldata-ajustements-v1.js"; import { MappingCreatureArme } from "../item/mapping-creature-arme.mjs"; import RollDialog from "../roll/roll-dialog.mjs"; -import { ATTAQUE_ROLL_TYPES, DEFAULT_ROLL_TYPES, DIFF, DIFFS, ROLL_TYPE_ATTAQUE, ROLL_TYPE_COMP, ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_OEUVRE, ROLL_TYPE_POSSESSION, ROLL_TYPE_TACHE } from "../roll/roll-constants.mjs"; +import { ATTAQUE_ROLL_TYPES, DEFAULT_ROLL_TYPES, DIFF, ROLL_TYPE_ATTAQUE} from "../roll/roll-constants.mjs"; import { OptionsAvancees, ROLL_DIALOG_V2 } from "../settings/options-avancees.js"; import { PART_COMP } from "../roll/roll-part-comp.mjs"; import { RdDInitiative } from "../initiative.mjs"; import { RdDItemCompetenceCreature } from "../item-competencecreature.js"; -import { ACTIONS_POSSESSION, RdDPossessionV2 } from "../rdd-possession-v2.mjs"; +import { RdDPossessionV2 } from "../rdd-possession-v2.mjs"; /** * Classe de base pour les acteurs disposant de rêve (donc, pas des objets) From a243209c9063200fd2008a900e5b9cc3a84854e5 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 7 Dec 2025 01:18:00 +0100 Subject: [PATCH 09/17] Fix: selection parmi les cibles --- module/targets.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/targets.js b/module/targets.js index 2244acc7..bc628046 100644 --- a/module/targets.js +++ b/module/targets.js @@ -41,7 +41,7 @@ export class Targets { label: "Choisir une seule des cibles", list: targets.map(it => Targets.extractTokenData(it)) }; - DialogSelect.select(selectData, t => onSelectTarget(t.target)) + DialogSelect.select(selectData, target => onSelectTarget(targets.find(it => it.id == target.id))) } } } From ca2d17bd25d4a8aef9d20212ece1bd9a72f42a5f Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 7 Dec 2025 23:43:13 +0100 Subject: [PATCH 10/17] =?UTF-8?q?Encombrement=20avec=20d=C3=A9cimales?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/item.js | 10 +++++----- template.json | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/module/item.js b/module/item.js index b9813d1d..69c8d8a7 100644 --- a/module/item.js +++ b/module/item.js @@ -364,11 +364,11 @@ export class RdDItem extends Item { getEnc() { switch (this.type) { case ITEM_TYPES.service: - return 0; + return 0 case ITEM_TYPES.herbe: - return this.getEncHerbe(); + return this.getEncHerbe() } - return Math.max(this.system.encombrement ?? 0, 0); + return Math.max(this.system.encombrement ?? 0.0, 0.0); } getEncContenu() { @@ -384,9 +384,9 @@ export class RdDItem extends Item { getEncHerbe() { switch (this.system.categorie) { case 'Repos': case 'Soin': case 'Alchimie': - return encBrin; + return encBrin } - return this.system.encombrement; + return this.system.encombrement } diff --git a/template.json b/template.json index 7f9a96e7..d90140f4 100644 --- a/template.json +++ b/template.json @@ -37,7 +37,7 @@ "bonus": "", "manoeuvrabilite": "", "equipage": 0, - "capacite_encombrement": 0, + "capacite_encombrement": 0.0, "etat": { "resistance": { "type": "number", @@ -193,7 +193,7 @@ }, "encombrement": { "type": "number", - "value": 0, + "value": 0.0, "label": "Encombrement", "derivee": true }, @@ -391,7 +391,7 @@ }, "encombrement": { "type": "number", - "value": 0, + "value": 0.0, "label": "Encombrement", "derivee": true }, @@ -600,7 +600,7 @@ "equipe": false }, "inventaire": { - "encombrement": 0, + "encombrement": 0.0, "quantite": 1, "qualite": 0, "cout": 0.0, From b26c39cf21658c8b984edc0787c2e3d21e26bf4c Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 6 Dec 2025 00:51:18 +0100 Subject: [PATCH 11/17] =?UTF-8?q?Ajout=20des=20options=20d'appr=C3=A9ciati?= =?UTF-8?q?on?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L'appréciation utilise: - un niveau de qualité (qui réutilise la qualité sur les items en ayant) - un bon moment (coeur/musique/...) - un niveau de jet de moral - une caractéristique (perception) - une compétence Les bon moments passés sont remis à zéro lors du passage de château dormant. Ajout des jets de moral très heureux. Ajout de jet d'appréciation sur les résultats des oeuvres et des jeux. --- changelog.md | 9 + css/foundryvtt-reve-de-dragon.css | 26 ++- less/foundryvtt-reve-de-dragon.less | 57 +++--- less/roll-chat.less | 13 +- module/actor-sheet.js | 7 +- module/actor.js | 78 ++++---- module/coeur/rdd-coeur.js | 3 +- module/dialog-select.js | 1 + module/item-sheet.js | 6 +- module/item.js | 17 +- module/migrations.js | 39 +++- module/moral/apprecier.mjs | 166 ++++++++++++++++++ module/rdd-utility.js | 38 +++- module/roll/chat-roll-result.mjs | 18 +- module/roll/roll-constants.mjs | 2 +- module/roll/roll-dialog.mjs | 2 + module/roll/roll-part-apprecier.mjs | 32 ++++ module/roll/roll-part-comp.mjs | 7 +- module/roll/roll-part-diff.mjs | 2 +- module/roll/roll-type-comp.mjs | 7 +- module/roll/roll-type-cuisine.mjs | 4 +- module/roll/roll-type-jeu.mjs | 7 +- module/roll/roll-type-oeuvre.mjs | 8 +- module/settings/system-compendiums.js | 6 +- module/sommeil/dialog-repos.js | 4 +- module/targets.js | 8 + template.json | 28 ++- templates/actor/comp-creature.hbs | 2 +- templates/enum-competence.hbs | 2 +- templates/enum-draconic.hbs | 2 +- templates/item/arme-sheet.hbs | 4 +- templates/item/armure-sheet.hbs | 4 +- templates/item/blessure-sheet.hbs | 2 +- templates/item/casetmr-sheet.hbs | 4 +- templates/item/chant-sheet.hbs | 5 +- templates/item/competence-sheet.hbs | 2 +- templates/item/competencecreature-sheet.hbs | 4 +- templates/item/conteneur-sheet.hbs | 4 +- templates/item/danse-sheet.hbs | 5 +- templates/item/empoignade-sheet.hbs | 4 +- .../item/enum-appreciation-bonmoment.hbs | 6 + templates/item/enum-appreciation-carac.hbs | 6 + templates/item/enum-appreciation-moral.hbs | 4 + templates/item/faune-sheet.hbs | 2 +- templates/item/gemme-sheet.hbs | 2 +- templates/item/herbe-sheet.hbs | 2 +- templates/item/icon-arme-broken.hbs | 2 +- templates/item/ingredient-sheet.hbs | 4 +- templates/item/item-sheet.hbs | 2 +- templates/item/jeu-sheet.hbs | 5 +- templates/item/livre-sheet.hbs | 2 +- templates/item/maladie-sheet.hbs | 2 +- templates/item/meditation-sheet.hbs | 4 +- templates/item/musique-sheet.hbs | 6 +- templates/item/nombreastral-sheet.hbs | 2 +- templates/item/nourritureboisson-sheet.hbs | 6 +- templates/item/objet-sheet.hbs | 4 +- templates/item/oeuvre-sheet.hbs | 5 +- templates/item/partial-appreciable.hbs | 54 ++++++ .../partial-description.hbs} | 3 +- .../partial-frequence.hbs} | 0 .../partial-hautrevant.hbs} | 0 .../partial-header.hbs} | 0 templates/item/plante-sheet.hbs | 2 +- templates/item/poison-sheet.hbs | 2 +- templates/item/possession-sheet.hbs | 2 +- templates/item/potion-sheet.hbs | 2 +- templates/item/queue-sheet.hbs | 8 +- templates/item/race-sheet.hbs | 4 +- templates/item/recettealchimique-sheet.hbs | 4 +- templates/item/recettecuisine-sheet.hbs | 4 +- templates/item/rencontre-sheet.hbs | 6 +- templates/item/service-sheet.hbs | 13 +- templates/item/signedraconique-sheet.hbs | 2 +- templates/item/sort-sheet.hbs | 4 +- templates/item/sortreserve-sheet.hbs | 2 +- templates/item/souffle-sheet.hbs | 8 +- templates/item/tache-sheet.hbs | 4 +- templates/item/tete-sheet.hbs | 8 +- templates/roll/result/chat-comp.hbs | 13 +- templates/roll/result/chat-cuisine.hbs | 5 +- templates/roll/result/chat-jeu.hbs | 9 +- templates/roll/result/chat-oeuvre.hbs | 9 +- templates/roll/result/chat-sort.hbs | 8 +- .../roll/result/partial-appreciation.hbs | 15 ++ templates/roll/result/partial-apprecier.hbs | 5 + templates/roll/roll-part-apprecier.hbs | 26 +++ 87 files changed, 725 insertions(+), 202 deletions(-) create mode 100644 module/moral/apprecier.mjs create mode 100644 module/roll/roll-part-apprecier.mjs create mode 100644 templates/item/enum-appreciation-bonmoment.hbs create mode 100644 templates/item/enum-appreciation-carac.hbs create mode 100644 templates/item/enum-appreciation-moral.hbs create mode 100644 templates/item/partial-appreciable.hbs rename templates/{partial-item-description.hbs => item/partial-description.hbs} (97%) rename templates/{partial-item-frequence.hbs => item/partial-frequence.hbs} (100%) rename templates/{partial-item-hautrevant.hbs => item/partial-hautrevant.hbs} (100%) rename templates/{header-item.hbs => item/partial-header.hbs} (100%) create mode 100644 templates/roll/result/partial-appreciation.hbs create mode 100644 templates/roll/result/partial-apprecier.hbs create mode 100644 templates/roll/roll-part-apprecier.hbs diff --git a/changelog.md b/changelog.md index 02b4a6e2..74c06454 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,15 @@ ## 13.0.21 - La folie d'Illysis +- Jets d'appréciation et de moral + - concerne la danse, musique, chant, jeu, les oeuvres, la nourriture, les services + - gestion des compétences d'appréciation pour les oeuvres + - pas de jet de moral si la qualité n'est pas suffisante (inférieure au moral, + à la compétence, moral déjà gagné pour la même raison) + - jet d'appréciation avec en option la compétence et la qualité + - jet de moral très heureux (pour Spasme) + - les jets de moral sont liés à des "bon moments" + - la liste des bons moments passés par un acteur est remise à zéro à Château Dormant - La zone de saisie dans les journaux est mieux adaptée - Fenêtre de jet v2 - les possessions sont maintenant gérées avec les fenêtres V2 diff --git a/css/foundryvtt-reve-de-dragon.css b/css/foundryvtt-reve-de-dragon.css index eefcca81..bc33c35f 100644 --- a/css/foundryvtt-reve-de-dragon.css +++ b/css/foundryvtt-reve-de-dragon.css @@ -682,7 +682,7 @@ select, .system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat { font-family: CaslonAntique; display: grid; - grid-template-areas: "img header buttons" "img resume buttons" "details details details" "actions actions actions"; + grid-template-areas: "img header buttons" "img resume buttons" "details details details" "description description description" "actions actions actions"; grid-template-columns: 3rem 1fr 1.4rem; grid-template-rows: max-content max-content max-content max-content; gap: 0 0.5rem; @@ -738,6 +738,17 @@ select, .system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-actions a img { margin-right: 0.5rem; } +.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-description, +.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-description { + grid-area: description; + text-align: justify; + display: flex; + flex-direction: column; +} +.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-description div, +.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-description div { + display: block; +} .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons, .system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons { grid-area: buttons; @@ -1388,12 +1399,22 @@ select, margin-inline: 0.1rem; margin-block: 0.1rem; } +.system-foundryvtt-reve-de-dragon .prosemirror menu { + background-color: var(--color-background-chat-message); +} .system-foundryvtt-reve-de-dragon .app.sheet fieldset :is(label, input) { font-family: CaslonAntique; text-align: justify; font-size: 1rem; letter-spacing: 1px; } +.system-foundryvtt-reve-de-dragon .app.sheet input.attribute-value { + background-color: rgba(0, 0, 0, 0.05); + border: 1px solid var(--color-border-light-tertiary); + padding: 1px 3px; + height: var(--form-field-height); + border-radius: 3px; +} .system-foundryvtt-reve-de-dragon .app.sheet div.form-group { clear: both; display: flex; @@ -1402,9 +1423,6 @@ select, margin: 0.1rem 0; align-items: center; } -.system-foundryvtt-reve-de-dragon .prosemirror menu { - background-color: var(--color-background-chat-message); -} .system-foundryvtt-reve-de-dragon .app.sheet .editor.prosemirror { height: fit-content; min-height: 6rem; diff --git a/less/foundryvtt-reve-de-dragon.less b/less/foundryvtt-reve-de-dragon.less index 4d59ed6f..1aff0122 100644 --- a/less/foundryvtt-reve-de-dragon.less +++ b/less/foundryvtt-reve-de-dragon.less @@ -689,6 +689,7 @@ } } } + fieldset { border-style: groove; border-width: 0.1rem; @@ -697,34 +698,48 @@ margin-inline: 0.1rem; margin-block: 0.1rem; } - .app.sheet fieldset :is(label, input) { - font-family: CaslonAntique; - text-align: justify; - font-size: 1rem; - letter-spacing: 1px; - } - .app.sheet div.form-group { - clear: both; - display: flex; - flex-direction: row; - flex-wrap: wrap; - margin: 0.1rem 0; - align-items: center; - } .prosemirror { menu { background-color: var(--color-background-chat-message); } } - .app.sheet .editor.prosemirror { - height: fit-content; - min-height: 6rem; - .editor-container { + + .app.sheet{ + fieldset :is(label, input) { + font-family: CaslonAntique; + text-align: justify; + font-size: 1rem; + letter-spacing: 1px; + } + + input.attribute-value { + background-color: rgba(0, 0, 0, 0.05); + border: 1px solid var(--color-border-light-tertiary); + padding: 1px 3px; + height: var(--form-field-height); + border-radius: 3px; + } + + div.form-group { + clear: both; + display: flex; + flex-direction: row; + flex-wrap: wrap; + margin: 0.1rem 0; + align-items: center; + } + + .editor.prosemirror { + height: fit-content; min-height: 6rem; - height: calc(100% - 3rem); - margin: 0; - flex: none; + + .editor-container { + min-height: 6rem; + height: calc(100% - 3rem); + margin: 0; + flex: none; + } } } .app.sheet.journal-entry-page .editor.prosemirror{ diff --git a/less/roll-chat.less b/less/roll-chat.less index aa77534d..ac61159c 100644 --- a/less/roll-chat.less +++ b/less/roll-chat.less @@ -6,7 +6,9 @@ "img header buttons" "img resume buttons" "details details details" - "actions actions actions"; + "description description description" + "actions actions actions" + ; grid-template-columns: 3rem 1fr 1.4rem; grid-template-rows: max-content max-content max-content max-content; gap: 0 0.5rem; @@ -53,6 +55,15 @@ } } } + div.chat-description { + grid-area: description; + text-align: justify; + display: flex; + flex-direction: column; + div { + display: block; + } + } div.chat-buttons { grid-area: buttons; diff --git a/module/actor-sheet.js b/module/actor-sheet.js index ae01d989..db2e623c 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -18,6 +18,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 { RdDTextEditor } from "./apps/rdd-text-roll-editor.js"; +import { MORAL } from "./moral/apprecier.mjs"; /* -------------------------------------------- */ /** @@ -275,9 +276,9 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { this.html.find('.seuil-reve-value').change(async event => await this.actor.setPointsDeSeuil(event.currentTarget.value)) this.html.find('.stress-test').click(async event => await this.actor.transformerStress()) - this.html.find('.moral-malheureux').click(async event => await this.actor.jetDeMoral('malheureuse')) - this.html.find('.moral-neutre').click(async event => await this.actor.jetDeMoral('neutre')) - this.html.find('.moral-heureux').click(async event => await this.actor.jetDeMoral('heureuse')) + this.html.find('.moral-malheureux').click(async event => await this.actor.jetDeMoral(MORAL.MALHEUREUX)) + this.html.find('.moral-neutre').click(async event => await this.actor.jetDeMoral(MORAL.NEUTRE)) + this.html.find('.moral-heureux').click(async event => await this.actor.jetDeMoral(MORAL.HEUREUX)) this.html.find('.button-ethylisme').click(async event => await this.actor.jetEthylisme()) this.html.find('.ptreve-actuel-plus').click(async event => await this.actor.reveActuelIncDec(1)) diff --git a/module/actor.js b/module/actor.js index a536f06d..4af2fc51 100644 --- a/module/actor.js +++ b/module/actor.js @@ -19,7 +19,7 @@ import { DialogConsommer } from "./dialog-item-consommer.js"; import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js"; import { RollDataAjustements } from "./rolldata-ajustements-v1.js"; import { RdDPossession } from "./rdd-possession.js"; -import { ACTOR_TYPES, RDD_CONFIG, renderTemplate, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; +import { ACTOR_TYPES, renderTemplate, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; import { RdDConfirm } from "./rdd-confirm.js"; import { DialogRepos } from "./sommeil/dialog-repos.js"; import { RdDBaseActor } from "./actor/base-actor.js"; @@ -53,6 +53,7 @@ import { PART_COMP } from "./roll/roll-part-comp.mjs"; import { PART_OEUVRE } from "./roll/roll-part-oeuvre.mjs"; import { PART_CUISINE } from "./roll/roll-part-cuisine.mjs"; import { RdDPossessionV2 } from "./rdd-possession-v2.mjs"; +import { MORAL, SITUATION_MORAL } from "./moral/apprecier.mjs"; export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre'] @@ -362,15 +363,15 @@ export class RdDActor extends RdDBaseActorSang { content: "" }; - await this._recuperationSante(message); - await this._recupereMoralChateauDormant(message); - await this._recupereChance(); - await this.transformerStress(); - await this.retourSeuilDeReve(message); - await this.setBonusPotionSoin(0); - await this.retourSust(message); - await this.$perteReveEnchantementsChateauDormants(); - await this.$suppressionLancementsSort(); + await this._recuperationSante(message) + await this._recupereMoralChateauDormant(message) + await this._recupereChance() + await this.transformerStress() + await this.retourSeuilDeReve(message) + await this.setBonusPotionSoin(0) + await this.retourSust(message) + await this.$perteReveEnchantementsChateauDormants() + await this.$suppressionLancementsSort() await RdDCoeur.applyCoeurChateauDormant(this, message); if (message.content != "") { message.content = `A la fin Chateau Dormant, ${message.content}
Un nouveau jour se lève`; @@ -414,11 +415,13 @@ export class RdDActor extends RdDBaseActorSang { } async _recupereMoralChateauDormant(message) { + await this.update({ 'system.compteurs.bonmoments': [] }, { render: false }) + if (!ReglesOptionnelles.isUsing("recuperation-moral")) { return } - const etatMoral = this.system.sommeil?.moral ?? 'neutre'; - const jetMoral = await this._jetDeMoral(etatMoral); - message.content += ` -- le jet de moral est ${etatMoral}, le moral ` + this._messageAjustementMoral(jetMoral.ajustement); + const etatMoral = this.system.sommeil?.moral ?? MORAL.NEUTRE + const jetMoral = await this._jetDeMoral(etatMoral) + message.content += ` -- le jet de moral est ${etatMoral}, le moral ` + this._messageAjustementMoral(jetMoral.ajustement) } _messageAjustementMoral(ajustement) { @@ -1195,17 +1198,21 @@ export class RdDActor extends RdDBaseActorSang { } /* -------------------------------------------- */ - async jetDeMoral(situation, messageReussi = undefined, messageManque = undefined) { - const jetMoral = await this._jetDeMoral(situation); - const finMessage = (jetMoral.succes ? messageReussi : messageManque) ?? (jetMoral.ajustement == 0 ? "Vous gardez votre moral" : jetMoral.ajustement > 0 ? "Vous gagnez du moral" : "Vous perdez du moral"); + async jetDeMoral(situation, bonmoment = "") { + if (bonmoment != "" && bonmoment != undefined && this.system.compteurs.bonmoments.includes(bonmoment)) { + ui.notifications.info(`${this.name} a déjà gagné du moral après avoir passé un bon moment (${bonmoment}) pendant la journée, pas de gain de moral`) + return + } + const jetMoral = await this._jetDeMoral(situation, bonmoment) + const finMessage = (jetMoral.ajustement == 0 ? "Vous gardez votre moral" : jetMoral.ajustement > 0 ? "Vous gagnez du moral" : "Vous perdez du moral"); ChatMessage.create({ whisper: ChatUtility.getOwners(this), - content: `${finMessage} - jet ${jetMoral.succes ? "réussi" : "manqué"} en situation ${situation} (${jetMoral.jet}/${jetMoral.difficulte}).` - }); - return jetMoral.ajustement; + content: `${finMessage} - jet ${jetMoral.succes ? "réussi" : "manqué"} en situation ${SITUATION_MORAL[situation] ?? situation} (${jetMoral.jet}/${jetMoral.difficulte}).` + }) + return jetMoral.ajustement } - async _jetDeMoral(situation) { + async _jetDeMoral(situation, bonmoment = "") { const moralActuel = Misc.toInt(this.system.compteurs.moral.value); const jet = await RdDDice.rollTotal("1d20"); const difficulte = 10 + moralActuel; @@ -1217,14 +1224,18 @@ export class RdDActor extends RdDBaseActorSang { difficulte: difficulte, succes: succes, ajustement: this._calculAjustementMoral(succes, moralActuel, situation) - }; - await this.moralIncDec(jetMoral.ajustement); + } + await this.moralIncDec(jetMoral.ajustement, bonmoment); return jetMoral; } /* -------------------------------------------- */ - async moralIncDec(ajustementMoral) { + async moralIncDec(ajustementMoral, bonmoment = "") { if (ajustementMoral != 0) { + if (ajustementMoral > 0 && bonmoment != "" && bonmoment != undefined) { + const bonmoments = [...this.system.compteurs.bonmoments, bonmoment] + await this.update({ 'system.compteurs.bonmoments': bonmoments }, { render: false }) + } const startMoral = parseInt(this.system.compteurs.moral.value) const moralTheorique = startMoral + ajustementMoral if (moralTheorique > 3) { // exaltation @@ -1245,13 +1256,14 @@ export class RdDActor extends RdDBaseActorSang { /* -------------------------------------------- */ _calculAjustementMoral(succes, moral, situation) { switch (situation) { - case 'heureux': case 'heureuse': return succes ? 1 : 0; - case 'malheureuse': case 'malheureux': return succes ? 0 : -1; - case 'neutre': - if (succes && moral < 0) return 1; - if (!succes && moral > 0) return -1; + case MORAL.TRESHEUREUX: return succes ? 2 : 1 + case MORAL.HEUREUX: case 'heureuse': return succes ? 1 : 0 + case MORAL.MALHEUREUX: case 'malheureuse': return succes ? 0 : -1 + case MORAL.NEUTRE: + if (succes && moral < 0) return 1 + if (!succes && moral > 0) return -1 } - return 0; + return 0 } /* -------------------------------------------- */ @@ -1331,7 +1343,7 @@ export class RdDActor extends RdDBaseActorSang { await this.apprecier(CARACS.ODORATGOUT, 'cuisine', item.system.qualite, item.system.boisson ? "apprécie la boisson" : "apprécie le plat"); } else if (seForcer) { - await this.jetDeMoral('malheureux'); + await this.jetDeMoral(MORAL.MALHEUREUX); } else { return false; @@ -1362,7 +1374,7 @@ export class RdDActor extends RdDBaseActorSang { } const rolled = await this.doRollCaracCompetence(carac, undefined, 0, { title }); if (rolled?.isSuccess) { - await this.jetDeMoral('heureux'); + await this.jetDeMoral(MORAL.HEUREUX); } } @@ -1429,7 +1441,7 @@ export class RdDActor extends RdDBaseActorSang { ethylismeData.perteEndurance = await this.santeIncDec("endurance", -perte); if (!ethylisme.jet_moral) { - ethylismeData.jetMoral = await this._jetDeMoral('heureuse'); + ethylismeData.jetMoral = await this._jetDeMoral(MORAL.HEUREUX, "Ethylisme"); if (ethylismeData.jetMoral.ajustement == 1) { ethylismeData.moralAlcool = 'heureux'; ethylisme.jet_moral = true; @@ -1437,7 +1449,7 @@ export class RdDActor extends RdDBaseActorSang { ethylismeData.jetMoral.ajustement = -1; ethylismeData.moralAlcool = 'triste'; ethylisme.jet_moral = true; - await this.moralIncDec(-1); + await this.moralIncDec(-1, "Ethylisme"); } } if (ethylisme.value < 0) { diff --git a/module/coeur/rdd-coeur.js b/module/coeur/rdd-coeur.js index 4954f725..5321adcb 100644 --- a/module/coeur/rdd-coeur.js +++ b/module/coeur/rdd-coeur.js @@ -1,6 +1,7 @@ import { RdDBaseActor } from "../actor/base-actor.js"; import { ChatUtility } from "../chat-utility.js"; import { renderTemplate } from "../constants.js"; +import { MORAL } from "../moral/apprecier.mjs"; const INFO_COEUR = 'info-coeur'; @@ -122,7 +123,7 @@ export class RdDCoeur { const diff = Math.abs(infoCoeur.source.jetTendre - infoCoeur.target.jetTendre) for (let amoureux of [infoCoeur.source, infoCoeur.target]) { const actorAmoureux = game.actors.get(amoureux.actor.id); - amoureux.situation = diff <= amoureux.coeur ? 'heureux' : 'neutre' + amoureux.situation = diff <= amoureux.coeur ? MORAL.HEUREUX : MORAL.NEUTRE amoureux.gainMoral = await actorAmoureux.jetDeMoral(amoureux.situation) } const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-accepter-tendre-moment.hbs`, infoCoeur) diff --git a/module/dialog-select.js b/module/dialog-select.js index 33253e2a..128f80d9 100644 --- a/module/dialog-select.js +++ b/module/dialog-select.js @@ -3,6 +3,7 @@ import { renderTemplate } from "./constants.js" export class DialogSelect extends Dialog { static extractIdNameImg(it) { return { id: it.id, name: it.name, img: it.img } } + static async select(selectionData, onSelectChoice) { const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-select.hbs", selectionData) diff --git a/module/item-sheet.js b/module/item-sheet.js index 5b3cc994..b27cc56a 100644 --- a/module/item-sheet.js +++ b/module/item-sheet.js @@ -14,6 +14,8 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js"; import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js"; import { ItemAction } from "./item/item-actions.js"; +import { SANS_COMPETENCE } from "./item/base-items.js"; +import { Apprecier } from "./moral/apprecier.mjs"; /** * Extend the basic ItemSheet for RdD specific items @@ -89,6 +91,7 @@ export class RdDItemSheetV1 extends foundry.appv1.sheets.ItemSheet { /* -------------------------------------------- */ async getData() { + const competences = (await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage)) let formData = { title: this.item.name, id: this.item.id, @@ -101,8 +104,9 @@ export class RdDItemSheetV1 extends foundry.appv1.sheets.ItemSheet { descriptionmj: await RdDTextEditor.enrichHTML(this.item.system.descriptionmj, this.item), isComestible: this.item.getUtilisationCuisine(), options: RdDSheetUtility.mergeDocumentRights({}, this.item, this.isEditable), - competences: await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage), + competences: [SANS_COMPETENCE, ...competences], categories: RdDItem.getCategories(this.item.type), + isAppreciable: Apprecier.isAppreciable(this.item) } if (this.item.type == ITEM_TYPES.competencecreature) { diff --git a/module/item.js b/module/item.js index 69c8d8a7..d769b779 100644 --- a/module/item.js +++ b/module/item.js @@ -28,7 +28,7 @@ const typesInventaireMateriel = [ ] const typesInventaire = { materiel: typesInventaireMateriel, - all: ['service'].concat(typesInventaireMateriel), + all: [ITEM_TYPES.service].concat(typesInventaireMateriel), } const typesObjetsOeuvres = [ITEM_TYPES.oeuvre, ITEM_TYPES.recettecuisine, ITEM_TYPES.musique, ITEM_TYPES.chant, ITEM_TYPES.danse, ITEM_TYPES.jeu] @@ -36,6 +36,10 @@ const typesObjetsDraconiques = [ITEM_TYPES.queue, ITEM_TYPES.ombre, ITEM_TYPES.s const typesObjetsConnaissance = [ITEM_TYPES.meditation, ITEM_TYPES.recettealchimique, ITEM_TYPES.sort] const typesObjetsEffet = [ITEM_TYPES.possession, ITEM_TYPES.poison, ITEM_TYPES.maladie, ITEM_TYPES.blessure] const typesObjetsCompetence = [ITEM_TYPES.competence, ITEM_TYPES.competencecreature] +const typesAppreciable = [ + ITEM_TYPES.oeuvre, ITEM_TYPES.musique, ITEM_TYPES.chant, ITEM_TYPES.danse, ITEM_TYPES.nourritureboisson, + ITEM_TYPES.jeu, ITEM_TYPES.service +] const typesObjetsTemporels = [ITEM_TYPES.blessure, ITEM_TYPES.poison, ITEM_TYPES.maladie, ITEM_TYPES.queue, ITEM_TYPES.ombre, ITEM_TYPES.souffle, ITEM_TYPES.signedraconique, ITEM_TYPES.rencontre] const typesObjetsEquipable = [ITEM_TYPES.arme, ITEM_TYPES.armure, ITEM_TYPES.objet]; const typesEnvironnement = typesInventaireMateriel; @@ -96,14 +100,14 @@ export class RdDItem extends Item { switch (field) { case 'quantite': if (ITEM_TYPES.conteneur == type) { - return false; + return false } break; case 'cout': if (ITEM_TYPES.monnaie == type) { return game.user.isGM; } - break; + break } return true; } @@ -180,10 +184,10 @@ export class RdDItem extends Item { isCompetencePersonnage() { return this.type == ITEM_TYPES.competence } isCompetenceCreature() { return this.type == ITEM_TYPES.competencecreature } - isConteneur() { return this.type == ITEM_TYPES.conteneur; } - isMonnaie() { return this.type == ITEM_TYPES.monnaie; } + isConteneur() { return this.type == ITEM_TYPES.conteneur } + isMonnaie() { return this.type == ITEM_TYPES.monnaie } isNourritureBoisson() { return this.type == ITEM_TYPES.nourritureboisson; } - isService() { return this.type == ITEM_TYPES.service; } + isService() { return this.type == ITEM_TYPES.service } isAttaque() { return false } isParade() { return false } isBouclier() { return false } @@ -214,6 +218,7 @@ export class RdDItem extends Item { isConnaissance() { return typesObjetsConnaissance.includes(this.type) } isInventaire(mode = 'materiel') { return RdDItem.getItemTypesInventaire(mode).includes(this.type); } + isAppreciable() { return typesAppreciable.includes(this.type) } isBoisson() { return this.isNourritureBoisson() && this.system.boisson; } isAlcool() { return this.isNourritureBoisson() && this.system.boisson && this.system.alcoolise; } isHerbeAPotion() { return this.type == ITEM_TYPES.herbe && (this.system.categorie == 'Soin' || this.system.categorie == 'Repos'); } diff --git a/module/migrations.js b/module/migrations.js index c09421b6..38814e25 100644 --- a/module/migrations.js +++ b/module/migrations.js @@ -8,6 +8,7 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDRaretes } from "./item/raretes.js"; import { VOIES_DRACONIC } from "./item-sort.js"; import { SystemCompendiums } from "./settings/system-compendiums.js"; +import { APPRECIATION } from "./moral/apprecier.mjs"; class Migration { get code() { return "sample"; } @@ -33,7 +34,6 @@ class Migration { await Item.updateDocuments(itemUpdates); } } - } class _1_5_34_migrationPngWebp { @@ -662,6 +662,37 @@ class _13_0_7_FixNiveauOeuvres extends Migration { } } +class _13_0_21_AjoutAppreciation extends Migration { + get code() { return "ajout-appreciation" } + get version() { return "13.0.21" } + + async migrate() { + await this.applyItemsUpdates(items => items + .filter(it => it.isAppreciable()) + .filter(it => this.getBaseAppreciation(it)) + .map(it => { + return { _id: it.id, 'system.appreciation': this.getBaseAppreciation(it) } + }) + ) + } + + getBaseAppreciation(item) { + switch (item.type) { + case ITEM_TYPES.nourritureboisson: return APPRECIATION.CUISINE + case ITEM_TYPES.service: return APPRECIATION.SERVICE + case ITEM_TYPES.musique: return APPRECIATION.MUSIQUE + case ITEM_TYPES.chant: return APPRECIATION.CHANT + case ITEM_TYPES.danse: return APPRECIATION.DANSE + case ITEM_TYPES.oeuvre: { + const appreciation = foundry.utils.duplicate(APPRECIATION.OEUVRE) + appreciation.competence = item.system.competence + return appreciation + } + } + return undefined + } +} + export class Migrations { static getMigrations() { return [ @@ -687,6 +718,7 @@ export class Migrations { new _12_0_38_TachesEcriture(), new _13_0_4_FixReveActuel(), new _13_0_7_FixNiveauOeuvres(), + new _13_0_21_AjoutAppreciation(), ]; } @@ -707,7 +739,10 @@ export class Migrations { } if (foundry.utils.isNewerVersion(game.system.version, currentVersion)) { // if (true) { /* comment previous and uncomment here to test before upgrade */ - const migrations = Migrations.getMigrations().filter(m => foundry.utils.isNewerVersion(m.version, currentVersion)); + const migrations = Migrations.getMigrations().filter(m => foundry.utils.isNewerVersion(m.version, currentVersion) + /* uncomment and set the version to migrate to to force a migration */ + // ||m.version == "13.0.21" + ) if (migrations.length > 0) { migrations.sort((a, b) => this.compareVersions(a, b)); migrations.forEach(async (m) => { diff --git a/module/moral/apprecier.mjs b/module/moral/apprecier.mjs new file mode 100644 index 00000000..51e4d1f6 --- /dev/null +++ b/module/moral/apprecier.mjs @@ -0,0 +1,166 @@ +import { ITEM_TYPES } from "../constants.js" +import { SANS_COMPETENCE } from "../item/base-items.js" +import { CARACS } from "../rdd-carac.js" +import { RdDUtility } from "../rdd-utility.js" +import { DIFF } from "../roll/roll-constants.mjs" +import RollDialog from "../roll/roll-dialog.mjs" +import { PART_COMP } from "../roll/roll-part-comp.mjs" + +export const MORAL = { + MALHEUREUX: "malheureux", + NEUTRE: "neutre", + HEUREUX: "heureux", + TRESHEUREUX: "très heureux" +} +export const SITUATION_MORAL = { + [MORAL.MALHEUREUX]: "malheureuse", + [MORAL.NEUTRE]: "neutre", + [MORAL.HEUREUX]: "heureuse", + [MORAL.TRESHEUREUX]: "très heureuse", +} +export const APPRECIATION = { + CUISINE: { + bonmoment: "Cuisine", carac: CARACS.ODORATGOUT, competence: "Cuisine", + moral: MORAL.HEUREUX, jetComp: false, jetQualite: false, compMinimum: true + }, + MUSIQUE: { + bonmoment: "Musique", carac: CARACS.OUIE, competence: "Musique", + moral: MORAL.HEUREUX, jetComp: false, jetQualite: false, compMinimum: true + }, + CHANT: { + bonmoment: "Musique", carac: CARACS.OUIE, competence: "Chant", + moral: MORAL.HEUREUX, jetComp: false, jetQualite: false, compMinimum: true + }, + DANSE: { + bonmoment: "Spectacle", carac: CARACS.EMPATHIE, competence: "Danse", + moral: MORAL.HEUREUX, jetComp: false, jetQualite: false, compMinimum: true + }, + JEU: { + bonmoment: "Jeu", carac: CARACS.EMPATHIE, competence: "Jeu", + moral: MORAL.HEUREUX, jetComp: false, jetQualite: false, compMinimum: true + }, + OEUVRE: { + bonmoment: "Spectacle", carac: CARACS.EMPATHIE, competence: "", + moral: MORAL.HEUREUX, jetComp: false, jetQualite: false, compMinimum: true + }, + SERVICE: { + bonmoment: "Confort", carac: CARACS.EMPATHIE, competence: "", + moral: MORAL.HEUREUX, jetComp: false, jetQualite: false, compMinimum: false + }, +} + + +export class Apprecier { + + static isAppreciable(item) { + switch (item.type) { + case ITEM_TYPES.nourritureboisson: + case ITEM_TYPES.service: + return item.system.qualite > 0 + case ITEM_TYPES.chant: + case ITEM_TYPES.musique: + case ITEM_TYPES.danse: + case ITEM_TYPES.oeuvre: + case ITEM_TYPES.jeu: + return true + } + return false + } + + static qualite(qualite, roll = undefined, comp = undefined) { + if (roll && comp) { + return roll.rolled.isSuccess ? qualite : Math.min(qualite, comp.system.niveau) + } + return + } + + static getAppreciation(qualite, appreciable, roll = undefined, comp = undefined) { + return { + qualite: (roll?.rolled.ptQualite ?? 0) + Apprecier.qualite(qualite, roll, comp), + appreciation: foundry.utils.duplicate(appreciable.system.appreciation), + messages: [] + } + } + + static onClickApprecier(roll) { + const appreciation = roll.result.appreciation + if (appreciation.moral == "") { + return + } + RdDUtility.doWithSelectedActor( + actor => new Apprecier(actor, appreciation, roll.result.qualite).apprecier(), + actor => actor.isPersonnage()) + } + + constructor(actor, appreciation, qualite) { + this.actor = actor + this.appreciation = foundry.utils.duplicate(appreciation) + this.appreciation.situation = SITUATION_MORAL[appreciation.moral] + this.qualite = qualite + this.raisons = [] + } + + apprecier() { + if (this.qualite <= 0) { + this.raisons.push(`la qualité ${this.qualite} est négative.`) + } + if (this.qualite <= this.actor.getMoralTotal()) { + this.raisons.push(`la qualité de ${this.qualite} est inférieure au moral de ${this.actor.getMoralTotal()}.`) + } + const competence = this.actor.getCompetence(this.appreciation.competence) ?? SANS_COMPETENCE + if (this.appreciation.compMinimum && this.qualite <= competence.system.niveau && competence.system.niveau > 0) { + this.raisons.push(`la qualité ${this.qualite} est insuffisante pour le niveau ${competence.system.niveau} en ${this.appreciation.competence}`) + } + const bonmoment = this.appreciation.bonmoment + if (!["", undefined].includes(bonmoment) && this.actor.system.compteurs.bonmoments.includes(bonmoment)) { + this.raisons.push(`du moral a déjà été gagné pour cause de ${bonmoment}`) + } + + if (this.appreciation.carac != "") { + this.rollAppreciation() + } + else { + this.rollMoral() + } + } + + rollAppreciation() { + const competence = (this.appreciation.jetComp && this.appreciation.competence) ? this.appreciation.competence : "" + const rollData = { + ids: { actorId: this.actor.id }, + type: { allowed: [PART_COMP], current: PART_COMP, appreciation: true }, + selected: { + carac: { key: this.appreciation.carac, forced: true }, + comp: { key: competence, forced: true }, + diff: { type: DIFF.IMPOSEE }, + apprecier: { + appreciation: this.appreciation, + qualite: this.qualite, + raisons: this.raisons + } + } + } + RollDialog.create(rollData, { callbacks: [async r => await this.onRollAppreciation(r)] }) + } + + async onRollAppreciation(roll) { + if (roll.rolled.isSuccess) { + await this.rollMoral() + } + else { + if (this.appreciation.moral == MORAL.TRESHEUREUX) { + await this.rollMoral(MORAL.HEUREUX) + } + } + } + + async rollMoral(moral = undefined) { + if (this.raisons.length > 0) { + return + } + + moral = moral ?? this.appreciation.moral + // TODO: jet de moral + await this.actor.jetDeMoral(moral, this.appreciation.bonmoment) + } +} \ No newline at end of file diff --git a/module/rdd-utility.js b/module/rdd-utility.js index fa2085a0..ad8b56e9 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -18,7 +18,7 @@ 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 { ITEM_TYPES, RDD_CONFIG, SYSTEM_RDD } from "./constants.js"; +import { ACTOR_TYPES, ITEM_TYPES, RDD_CONFIG, SYSTEM_RDD } from "./constants.js"; import { RdDBaseActor } from "./actor/base-actor.js"; import { RdDCarac } from "./rdd-carac.js"; import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js"; @@ -26,6 +26,8 @@ import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js"; import { RdDItemCompetence } from "./item-competence.js"; import { Monnaie } from "./item-monnaie.js"; import { ItemAction } from "./item/item-actions.js"; +import { Targets } from "./targets.js"; +import { DialogSelect } from "./dialog-select.js"; /* -------------------------------------------- */ // This table starts at 0 -> niveau -10 @@ -180,9 +182,14 @@ export class RdDUtility { 'systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.hbs', 'systems/foundryvtt-reve-de-dragon/templates/item/partial-environnement.hbs', 'systems/foundryvtt-reve-de-dragon/templates/item/partial-tab-environnement.hbs', - 'systems/foundryvtt-reve-de-dragon/templates/header-item.hbs', - - 'systems/foundryvtt-reve-de-dragon/templates/item/queue-sheet.hbs', + 'systems/foundryvtt-reve-de-dragon/templates/item/partial-header.hbs', + 'systems/foundryvtt-reve-de-dragon/templates/item/partial-hautrevant.hbs', + 'systems/foundryvtt-reve-de-dragon/templates/item/partial-frequence.hbs', + 'systems/foundryvtt-reve-de-dragon/templates/item/partial-description.hbs', + 'systems/foundryvtt-reve-de-dragon/templates/item/partial-appreciable.hbs', + 'systems/foundryvtt-reve-de-dragon/templates/item/enum-appreciation-bonmoment.hbs', + 'systems/foundryvtt-reve-de-dragon/templates/item/enum-appreciation-carac.hbs', + 'systems/foundryvtt-reve-de-dragon/templates/item/enum-appreciation-moral.hbs', // partial enums 'systems/foundryvtt-reve-de-dragon/templates/enum-aspect-tarot.hbs', 'systems/foundryvtt-reve-de-dragon/templates/enum-base-competence.hbs', @@ -232,9 +239,6 @@ export class RdDUtility { 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-moral.hbs', 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-surenc.hbs', 'systems/foundryvtt-reve-de-dragon/templates/partial-select-carac.hbs', - 'systems/foundryvtt-reve-de-dragon/templates/partial-item-hautrevant.hbs', - 'systems/foundryvtt-reve-de-dragon/templates/partial-item-frequence.hbs', - 'systems/foundryvtt-reve-de-dragon/templates/partial-item-description.hbs', 'systems/foundryvtt-reve-de-dragon/templates/roll/explain.hbs', 'systems/foundryvtt-reve-de-dragon/templates/resolution-table.hbs', // Dialogs @@ -847,6 +851,26 @@ export class RdDUtility { return undefined; } + static doWithSelectedActor(onSelected = () => { }, filter = actor => true) { + const selected = RdDUtility.getSelectedActor() + if (selected) { + onSelected(selected) + } + else { + const actors = game.actors + .filter(it => it.getUserLevel(game.user) == CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) + .filter(it => ![ACTOR_TYPES.commerce, ACTOR_TYPES.vehicule].includes(it.type)) + .filter(filter) + const selectData = { + title: "Choisir un acteur", + label: "Choisir un acteur", + list: actors.map(it => Targets.extractActorData(it)) + }; + DialogSelect.select(selectData, it => onSelected(game.actors.get(it.id))) + } + + } + /* -------------------------------------------- */ static createMonnaie(name, cout, img = "", enc = 0.01) { let piece = { diff --git a/module/roll/chat-roll-result.mjs b/module/roll/chat-roll-result.mjs index 036b2f7a..14512801 100644 --- a/module/roll/chat-roll-result.mjs +++ b/module/roll/chat-roll-result.mjs @@ -15,6 +15,7 @@ import { RdDEmpoignade } from "../rdd-empoignade.js" import { Misc } from "../misc.js" import { RollBasicParts } from "./roll-basic-parts.mjs" import { RdDPossessionV2 } from "../rdd-possession-v2.mjs" +import { Apprecier } from "../moral/apprecier.mjs" export default class ChatRollResult { static init() { @@ -25,14 +26,16 @@ export default class ChatRollResult { static onReady() { foundry.applications.handlebars.loadTemplates({ - 'partial-infojet': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-infojet.hbs', 'partial-appel-chance': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-appel-chance.hbs', + 'partial-apprecier': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-apprecier.hbs', + 'partial-appreciation': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-appreciation.hbs', 'partial-attaque-particuliere': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-attaque-particuliere.hbs', 'partial-choix-maladresse': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-choix-maladresse.hbs', - 'partial-maladresse': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-maladresse.hbs', 'partial-encaissement': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-encaissement.hbs', - 'partial-recul-choc': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-recul-choc.hbs', + 'partial-infojet': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-infojet.hbs', 'partial-info-appel-moral': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-info-appel-moral.hbs', + 'partial-maladresse': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-maladresse.hbs', + 'partial-recul-choc': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-recul-choc.hbs', }) } @@ -64,7 +67,8 @@ export default class ChatRollResult { $isAppelChancePossible(roll) { return roll.active.actor.isPersonnage() && roll.rolled.isEchec && - RdDCarac.isActionPhysique(roll.current.carac?.key) + RdDCarac.isActionPhysique(roll.current.carac?.key) && + !roll.type.appreciation } $isShowEncaissement(roll) { @@ -142,6 +146,7 @@ export default class ChatRollResult { $(html).on("click", '.resister-recul', event => this.onClickRecul(event)) $(html).on("click", '.choix-particuliere', event => this.onClickChoixParticuliere(event)) $(html).on("click", '.faire-gouter', event => this.onClickFaireGouter(event)) + $(html).on("click", '.apprecier', event => this.onClickApprecier(event)) $(html).on("click", '.monter-tmr-normale', event => this.onClickMonteeTMR(event, 'normal')) $(html).on("click", '.monter-tmr-rapide', event => this.onClickMonteeTMR(event, 'rapide')) $(html).on("click", '.tirer-maladresse', event => this.onClickTirerMaladresse(event)) @@ -313,6 +318,11 @@ export default class ChatRollResult { } await new RollTypeCuisine().onFaireGouter(savedRoll) } + async onClickApprecier(event) { + const chatMessage = ChatUtility.getChatMessage(event) + const savedRoll = this.loadChatMessageRoll(chatMessage) + await Apprecier.onClickApprecier(savedRoll) + } async onClickMonteeTMR(event, mode) { const chatMessage = ChatUtility.getChatMessage(event) diff --git a/module/roll/roll-constants.mjs b/module/roll/roll-constants.mjs index d9733e0c..4e2103af 100644 --- a/module/roll/roll-constants.mjs +++ b/module/roll/roll-constants.mjs @@ -28,7 +28,7 @@ export const DIFF = { export const DIFFS = { [DIFF.LIBRE]: { key: DIFF.LIBRE, label: "Difficulté libre", libre: true, visible: true, max: 0 }, [DIFF.ATTAQUE]: { key: DIFF.ATTAQUE, label: "Difficulté d'attaque", libre: true, visible: true, max: 0 }, - [DIFF.IMPOSEE]: { key: DIFF.IMPOSEE, label: "Difficulté imposée", libre: false, visible: true, max: 0 }, + [DIFF.IMPOSEE]: { key: DIFF.IMPOSEE, label: "Difficulté imposée", libre: false, visible: true, max: 20 }, [DIFF.DEFENSE]: { key: DIFF.DEFENSE, label: "Difficulté défense", libre: false, visible: true, max: 0 }, [DIFF.DEFAUT]: { key: DIFF.DEFAUT, label: "Difficulté", libre: true, visible: true, max: 5 }, [DIFF.AUCUN]: { key: DIFF.AUCUN, label: "", libre: false, visible: false, max: 0 }, diff --git a/module/roll/roll-dialog.mjs b/module/roll/roll-dialog.mjs index 601cc79e..6076d4e9 100644 --- a/module/roll/roll-dialog.mjs +++ b/module/roll/roll-dialog.mjs @@ -50,6 +50,7 @@ import { RollPartEcailles } from "./roll-part-ecailles.mjs"; import { RollPartResistance } from "./roll-part-resistance.mjs"; import { RollTypePossession } from "./roll-type-possession.mjs"; import { RollPartPossession } from "./roll-part-possession.mjs"; +import { RollPartApprecier } from "./roll-part-apprecier.mjs"; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api @@ -78,6 +79,7 @@ const ROLL_PARTS = [ new RollPartComp(), new RollPartDiff(), + new RollPartApprecier(), new RollPartAttaque(), new RollPartPossession(), new RollPartDefense(), diff --git a/module/roll/roll-part-apprecier.mjs b/module/roll/roll-part-apprecier.mjs new file mode 100644 index 00000000..4b3b09c9 --- /dev/null +++ b/module/roll/roll-part-apprecier.mjs @@ -0,0 +1,32 @@ +import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"; + +export const PART_APPRECIER = "apprecier" + +export class RollPartApprecier extends RollPart { + + get code() { return PART_APPRECIER } + get section() { return ROLLDIALOG_SECTION.CHOIX } + + restore(rollData) { + this.setCurrent(rollData, this.getSaved(rollData)) + } + + store(rollData, targetData) { + this.setSaved(targetData, this.getCurrent(rollData)) + } + + visible(rollData) { + return rollData.type.appreciation + } + + getAjustements(rollData) { + const current = this.getCurrent(rollData) + if (current.appreciation.jetQualite){ + return [{ + label: 'Qualité', + value: Math.abs(current.qualite) + }] + } + return [] + } +} \ No newline at end of file diff --git a/module/roll/roll-part-comp.mjs b/module/roll/roll-part-comp.mjs index e38832be..baa04632 100644 --- a/module/roll/roll-part-comp.mjs +++ b/module/roll/roll-part-comp.mjs @@ -22,7 +22,12 @@ export class RollPartComp extends RollPartSelect { if (selected.forced) { refs.all = all.filter(comp => Grammar.equalsInsensitive(comp.label, selected.key)) if (refs.all.length == 0) { - refs.all = all.filter(comp => Grammar.includesLowerCaseNoAccent(comp.label, selected.key)) + if (selected.key.length > 0) { + refs.all = all.filter(comp => Grammar.includesLowerCaseNoAccent(comp.label, selected.key)) + } + else { + refs.all = all.filter(comp => comp == SANS_COMPETENCE) + } } } else { diff --git a/module/roll/roll-part-diff.mjs b/module/roll/roll-part-diff.mjs index 031fb6e4..02024bd1 100644 --- a/module/roll/roll-part-diff.mjs +++ b/module/roll/roll-part-diff.mjs @@ -32,7 +32,7 @@ export class RollPartDiff extends RollPart { } visible(rollData) { - if (EXCLUDED_ROLL_TYPES.includes(rollData.type.current)) { + if (EXCLUDED_ROLL_TYPES.includes(rollData.type.current) || rollData.type.appreciation) { return false } const current = this.getCurrent(rollData) diff --git a/module/roll/roll-type-comp.mjs b/module/roll/roll-type-comp.mjs index 5dddc40b..8ab56bca 100644 --- a/module/roll/roll-type-comp.mjs +++ b/module/roll/roll-type-comp.mjs @@ -5,7 +5,12 @@ export class RollTypeComp extends RollType { get code() { return ROLL_TYPE_COMP } get name() { return `Jet de caractéristique / compétence` } - title(rollData) { return `fait un jet ${rollData.type.opposed ? ' contre ' : ''}` } + title(rollData) { + if (rollData.type.appreciation) { + return "fait un jet d'appéciation" + } + return `fait un jet ${rollData.type.opposed ? ' contre ' : ''}` + } onSelect(rollData) { diff --git a/module/roll/roll-type-cuisine.mjs b/module/roll/roll-type-cuisine.mjs index c4b38d1f..021efb7a 100644 --- a/module/roll/roll-type-cuisine.mjs +++ b/module/roll/roll-type-cuisine.mjs @@ -1,4 +1,5 @@ import { ITEM_TYPES } from "../constants.js" +import { APPRECIATION } from "../moral/apprecier.mjs" import { RollBasicParts } from "./roll-basic-parts.mjs" import { DIFF, ROLL_TYPE_CUISINE } from "./roll-constants.mjs" import { PART_CUISINE } from "./roll-part-cuisine.mjs" @@ -49,7 +50,7 @@ export class RollTypeCuisine extends RollType { return result } onApplyImpacts(roll, impacts) { - if (roll.result.plat) { + if (roll.result.plat) { // le plat n'est pas créé immédiatement, il faut donc retrouver l'id roll.result.plat.id = impacts.findCreatedId('Item', roll.result.plat.id) } @@ -69,6 +70,7 @@ export class RollTypeCuisine extends RollType { quantite: current.proportions, qualite: result.qualite, cout: result.qualite > 0 ? (result.qualite * 0.01) : 0.01, + appreciation: APPRECIATION.CUISINE } } } diff --git a/module/roll/roll-type-jeu.mjs b/module/roll/roll-type-jeu.mjs index e46cb990..62245b3d 100644 --- a/module/roll/roll-type-jeu.mjs +++ b/module/roll/roll-type-jeu.mjs @@ -1,6 +1,7 @@ import { PART_JEU, RollPartJeu } from "./roll-part-jeu.mjs" import { RollType } from "./roll-type.mjs" import { DIFF, ROLL_TYPE_JEU } from "./roll-constants.mjs" +import { Apprecier } from "../moral/apprecier.mjs" export class RollTypeJeu extends RollType { @@ -20,4 +21,8 @@ export class RollTypeJeu extends RollType { RollPartJeu.forceCompJeu(rollData) } -} \ No newline at end of file + getResult(rollData, impacts) { + const current = rollData.current[PART_JEU] + return Apprecier.getAppreciation(current.qualite, current.jeu, rollData, current.comp) + } +} diff --git a/module/roll/roll-type-oeuvre.mjs b/module/roll/roll-type-oeuvre.mjs index 5033f246..b3680308 100644 --- a/module/roll/roll-type-oeuvre.mjs +++ b/module/roll/roll-type-oeuvre.mjs @@ -1,3 +1,4 @@ +import { Apprecier } from "../moral/apprecier.mjs" import { DIFF, ROLL_TYPE_OEUVRE } from "./roll-constants.mjs" import { PART_OEUVRE } from "./roll-part-oeuvre.mjs" import { RollType } from "./roll-type.mjs" @@ -18,12 +19,7 @@ export class RollTypeOeuvre extends RollType { getResult(rollData, impacts) { const current = rollData.current[PART_OEUVRE] - const qualite = rollData.rolled.isSuccess ? current.qualite : Math.min(current.qualite, current.comp.system.niveau) - return { - qualite: qualite + rollData.rolled.ptQualite, - messages: [] - } + return Apprecier.getAppreciation(current.qualite, current.oeuvre, rollData, current.comp) } - } diff --git a/module/settings/system-compendiums.js b/module/settings/system-compendiums.js index f602b80a..275dd5ce 100644 --- a/module/settings/system-compendiums.js +++ b/module/settings/system-compendiums.js @@ -68,18 +68,20 @@ export class SystemCompendiums extends FormApplication { if (pack?.metadata.type == docType) { return await pack.getDocuments(); } - return []; + return [] } static async getCompetences(actorType) { switch (actorType ?? 'personnage') { case 'personnage': return await SystemCompendiums.getWorldOrCompendiumItems('competence', 'competences') + .then(list => list.sort((a, b) => a.name.localeCompare(b.name))) case 'entite': case 'creature': return await SystemCompendiums.getWorldOrCompendiumItems('competencecreature', 'competences-creatures') - case 'vehicule': return []; + .then(list => list.sort((a, b) => a.name.localeCompare(b.name))) } + return [] } /* -------------------------------------------- */ diff --git a/module/sommeil/dialog-repos.js b/module/sommeil/dialog-repos.js index a7267e51..e2720c6a 100644 --- a/module/sommeil/dialog-repos.js +++ b/module/sommeil/dialog-repos.js @@ -9,12 +9,12 @@ export class DialogRepos extends Dialog { return } if (!ReglesOptionnelles.isUsing("chateau-dormant-gardien") || !actor.hasPlayerOwner) { - actor.system.sommeil = { + foundry.utils.mergeObject(actor.system.sommeil, { "nouveaujour": true, "insomnie": EffetsDraconiques.isSujetInsomnie(actor), "moral": "neutre", "heures": 4 - } + }) } const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/sommeil/dialog-repos.hbs", actor); const dialog = new DialogRepos(html, actor); diff --git a/module/targets.js b/module/targets.js index bc628046..f6c5b157 100644 --- a/module/targets.js +++ b/module/targets.js @@ -18,6 +18,14 @@ export class Targets { } } + static extractActorData(actor) { + return { + id: actor.id, + name: actor.prototypeToken?.name ?? actor.name, + img: actor.prototypeToken?.texture.src ?? actor.img ?? 'icons/svg/mystery-man.svg' + } + } + static buildActorTokenData(tokenId, actor) { return { id: tokenId, name: actor.name, img: actor.img ?? 'icons/svg/mystery-man.svg' }; } diff --git a/template.json b/template.json index d90140f4..a72968d6 100644 --- a/template.json +++ b/template.json @@ -493,7 +493,8 @@ "value": 0, "label": "Experience", "isInput": true - } + }, + "bonmoments": [] }, "sommeil": { "nouveaujour": false, @@ -607,6 +608,17 @@ "milieu": "", "environnement": [] }, + "appreciable": { + "appreciation": { + "moral": "", + "bonmoment": "", + "carac": "", + "competence": "", + "jetComp": false, + "jetQualite": false, + "compMinimum": true + } + }, "comestible": { "sust": 0, "exotisme": 0 @@ -754,7 +766,7 @@ "enchantabilite": 0 }, "nourritureboisson": { - "templates": ["description", "inventaire", "comestible"], + "templates": ["description", "inventaire", "comestible", "appreciable"], "cuisinier": "", "boisson": false, "desaltere": 0, @@ -809,16 +821,16 @@ "reposalchimique": false }, "service": { - "templates": ["description", "inventaire"], + "templates": ["description", "inventaire", "appreciable"], "moral": false }, "musique": { - "templates": ["description"], + "templates": ["description", "appreciable"], "niveau": 0, "reference": "" }, "danse": { - "templates": ["description"], + "templates": ["description", "appreciable"], "type": "", "agilite": false, "apparence": false, @@ -826,12 +838,12 @@ "reference": "" }, "chant": { - "templates": ["description"], + "templates": ["description", "appreciable"], "niveau": 0, "reference": "" }, "jeu": { - "templates": ["description"], + "templates": ["description", "appreciable"], "type": "", "base": "", "caraccomp": "", @@ -847,7 +859,7 @@ "reference": "" }, "oeuvre": { - "templates": ["description"], + "templates": ["description", "appreciable"], "default_carac": "", "competence": "", "niveau": 0, diff --git a/templates/actor/comp-creature.hbs b/templates/actor/comp-creature.hbs index 2baf2420..5bda35d7 100644 --- a/templates/actor/comp-creature.hbs +++ b/templates/actor/comp-creature.hbs @@ -2,7 +2,7 @@ {{/if}}
{{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.hbs"}} - {{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.hbs"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-description.hbs"}}
{{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-environnement.hbs"}} diff --git a/templates/item/armure-sheet.hbs b/templates/item/armure-sheet.hbs index b8c3a6a8..84616eae 100644 --- a/templates/item/armure-sheet.hbs +++ b/templates/item/armure-sheet.hbs @@ -1,5 +1,5 @@ - {{>"systems/foundryvtt-reve-de-dragon/templates/header-item.hbs"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-header.hbs"}}
{{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.hbs"}} - {{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.hbs"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-description.hbs"}} {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-environnement.hbs"}} diff --git a/templates/item/blessure-sheet.hbs b/templates/item/blessure-sheet.hbs index 69c03966..e53162e8 100644 --- a/templates/item/blessure-sheet.hbs +++ b/templates/item/blessure-sheet.hbs @@ -1,5 +1,5 @@ - {{>"systems/foundryvtt-reve-de-dragon/templates/header-item.hbs"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-header.hbs"}}
diff --git a/templates/item/casetmr-sheet.hbs b/templates/item/casetmr-sheet.hbs index 9ceae1e1..189aee0e 100644 --- a/templates/item/casetmr-sheet.hbs +++ b/templates/item/casetmr-sheet.hbs @@ -1,5 +1,5 @@ - {{>"systems/foundryvtt-reve-de-dragon/templates/header-item.hbs"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-header.hbs"}} {{!-- Sheet Body --}}
@@ -15,6 +15,6 @@
- {{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.hbs"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-description.hbs"}}
diff --git a/templates/item/chant-sheet.hbs b/templates/item/chant-sheet.hbs index fedadc82..e6fe9262 100644 --- a/templates/item/chant-sheet.hbs +++ b/templates/item/chant-sheet.hbs @@ -1,5 +1,5 @@
- {{>"systems/foundryvtt-reve-de-dragon/templates/header-item.hbs"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-header.hbs"}} {{!-- Sheet Body --}}
@@ -11,6 +11,7 @@
- {{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.hbs"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-appreciable.hbs"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-description.hbs"}}
diff --git a/templates/item/competence-sheet.hbs b/templates/item/competence-sheet.hbs index a539889f..1d254e8c 100644 --- a/templates/item/competence-sheet.hbs +++ b/templates/item/competence-sheet.hbs @@ -65,7 +65,7 @@
- {{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.hbs"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-description.hbs"}}
diff --git a/templates/item/competencecreature-sheet.hbs b/templates/item/competencecreature-sheet.hbs index 75fc4c8b..f5d52017 100644 --- a/templates/item/competencecreature-sheet.hbs +++ b/templates/item/competencecreature-sheet.hbs @@ -1,5 +1,5 @@
- {{>"systems/foundryvtt-reve-de-dragon/templates/header-item.hbs"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-header.hbs"}} {{!-- Sheet Body --}}
@@ -47,6 +47,6 @@
{{/if}} - {{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.hbs"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-description.hbs"}}
diff --git a/templates/item/conteneur-sheet.hbs b/templates/item/conteneur-sheet.hbs index d485c280..5db14d6b 100644 --- a/templates/item/conteneur-sheet.hbs +++ b/templates/item/conteneur-sheet.hbs @@ -1,5 +1,5 @@
- {{>"systems/foundryvtt-reve-de-dragon/templates/header-item.hbs"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/item/partial-header.hbs"}} {{!-- Sheet Body --}}