From 275c144ea291611bb35787431125a4706e311c84 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Tue, 9 Dec 2025 22:06:52 +0100 Subject: [PATCH 01/26] =?UTF-8?q?Pr=C3=A9paration=20v13.0.22?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelog.md b/changelog.md index 1e0aa615..0e0fe9e6 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,7 @@ # 13.0 +## 13.0.22 - Les reflets d'Illysis + ## 13.0.21 - La folie d'Illysis - Jets d'appréciation et de moral From 6882b4819c31c5c6999c01647849f5f31bd9addc Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Tue, 9 Dec 2025 22:07:18 +0100 Subject: [PATCH 02/26] Correction: ajout de notes --- changelog.md | 3 +++ module/dialog-chronologie.js | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 0e0fe9e6..101e3cd0 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,9 @@ ## 13.0.22 - Les reflets d'Illysis +- Corrections liées à Foundry v12/v13 + - Fix ajout de notes dans le journal par un joueur (/chrono, ou clic sur le libelé de l'heure dans l'horloge) + ## 13.0.21 - La folie d'Illysis - Jets d'appréciation et de moral diff --git a/module/dialog-chronologie.js b/module/dialog-chronologie.js index e53eb6c1..3c3f1654 100644 --- a/module/dialog-chronologie.js +++ b/module/dialog-chronologie.js @@ -70,7 +70,7 @@ export class DialogChronologie extends Dialog { async ajouter() { await this.forceValidation(); const { journalId, journalEntry } = this.findJournal(); - if (journalEntry?.canUserModify(game.user)) { + if (journalEntry?.canUserModify(game.user, 'update')) { const journalParameters = this.extractJournalParameters(); const jour = journalParameters.dateRdD.jour; From 894161c0bffdbfb1c1766de75407a27591d6b875 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Tue, 9 Dec 2025 23:21:21 +0100 Subject: [PATCH 03/26] =?UTF-8?q?Fix:=20Encombrement=20d=C3=A9cimal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- changelog.md | 3 +++ module/actor/base-actor.js | 2 +- module/common/inventaire.mjs | 2 +- module/migrations.js | 21 +++++++++++++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 101e3cd0..1f66fea5 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,9 @@ ## 13.0.22 - Les reflets d'Illysis +- Corrections diverses + - l'encombrement total est affiché avec deux décimales + - le poids des monnaies est de nouveau décimal - Corrections liées à Foundry v12/v13 - Fix ajout de notes dans le journal par un joueur (/chrono, ou clic sur le libelé de l'heure dans l'horloge) diff --git a/module/actor/base-actor.js b/module/actor/base-actor.js index 0c954493..17a3cb6d 100644 --- a/module/actor/base-actor.js +++ b/module/actor/base-actor.js @@ -594,7 +594,7 @@ export class RdDBaseActor extends Actor { } getEncTotal() { - return Math.floor(this.encTotal ?? 0) + return Number(this.encTotal?.toFixed(2) ?? 0.00) } async createItem(type, name = undefined) { diff --git a/module/common/inventaire.mjs b/module/common/inventaire.mjs index 60b5b0b0..03d72596 100644 --- a/module/common/inventaire.mjs +++ b/module/common/inventaire.mjs @@ -7,7 +7,7 @@ const fields = foundry.data.fields export class CommonInventaire extends CommonTemplate { fields() { return { - encombrement: new fields.NumberField({ label: "Encombrement", initial: 0, ...INTEGER }), + encombrement: new fields.NumberField({ label: "Encombrement", initial: 0, ...DECIMAL }), quantite: new fields.NumberField({ label: "Quantité", initial: 1, ...INTEGER }), qualite: new fields.NumberField({ label: "Qualité", initial: 0, ...INTEGER_SIGNED }), cout: new fields.NumberField({ label: "Coût", initial: 0.0, ...DECIMAL }), diff --git a/module/migrations.js b/module/migrations.js index 38814e25..ee3c0ae3 100644 --- a/module/migrations.js +++ b/module/migrations.js @@ -693,6 +693,26 @@ class _13_0_21_AjoutAppreciation extends Migration { } } +class _13_0_22_PoidsDesMonnaies extends Migration { + get code() { return "poid-monnaies" } + get version() { return "13.0.22" } + + async migrate() { + await this.applyItemsUpdates(items => items + .filter(it => it.type == ITEM_TYPES.monnaie) + .map(it => { + return { _id: it.id, 'system.encombrement': this.poids(it) } + }) + ) + } + poids(monnaie) { + if (monnaie.system.cout < 0.05) return 0.001 + if (monnaie.system.cout < 0.5) return 0.002 + if (monnaie.system.cout < 5) return 0.003 + return 0.004 + } +} + export class Migrations { static getMigrations() { return [ @@ -719,6 +739,7 @@ export class Migrations { new _13_0_4_FixReveActuel(), new _13_0_7_FixNiveauOeuvres(), new _13_0_21_AjoutAppreciation(), + new _13_0_22_PoidsDesMonnaies(), ]; } From 697247e93152ce0005c6e5ec76a36303fe777599 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Tue, 9 Dec 2025 23:35:27 +0100 Subject: [PATCH 04/26] =?UTF-8?q?Fix:=20protection=20sur=20actions=20sans?= =?UTF-8?q?=20acteur/propri=C3=A9t=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cas rencontré une fois, un jet de chance d'un autre joueur, pouvait être tenté. Cas plus étrange, un jet de chance alors que le jet sauvegardé n'avait pas d'actorId --- module/actor-sheet.js | 4 +- module/misc.js | 6 +- module/rdd-combat.js | 2 +- module/roll/chat-roll-result.mjs | 97 +++++++++++++++++++------------- 4 files changed, 65 insertions(+), 44 deletions(-) diff --git a/module/actor-sheet.js b/module/actor-sheet.js index db2e623c..9e62226d 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -9,7 +9,7 @@ import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { RdDSheetUtility } from "./rdd-sheet-utility.js"; import { MAINS_DIRECTRICES } from "./actor.js"; import { RdDBaseActorReveSheet } from "./actor/base-actor-reve-sheet.js"; -import { ITEM_TYPES } from "./constants.js"; +import { ACTOR_TYPES, ITEM_TYPES } from "./constants.js"; import { RdDItem } from "./item.js"; import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemBlessure } from "./item/blessure.js"; @@ -58,7 +58,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { this.timerRecherche = undefined; - if (formData.type == 'personnage') { + if (formData.type == ACTOR_TYPES.personnage) { formData.options.mainsDirectrices = MAINS_DIRECTRICES; formData.byCateg = Misc.classify(formData.competences, it => it.system.categorie) formData.calc.comptageArchetype = RdDItemCompetence.computeResumeArchetype(formData.competences); diff --git a/module/misc.js b/module/misc.js index 6e6808eb..38417bb6 100644 --- a/module/misc.js +++ b/module/misc.js @@ -233,16 +233,16 @@ export class Misc { if (Misc.isOwnerPlayer(document)) { return await action(document) } else { - return await orElse(document) + return await orElse(document ?? {name: ''}) } } static isOwnerPlayer(document) { - return document.testUserPermission && document.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) + return document && document.testUserPermission && document.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) } static isFirstOwnerPlayer(document) { - if (!document.testUserPermission) { + if (!document?.testUserPermission) { return false } return game.users.find(u => document.testUserPermission(u, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)) == game.user diff --git a/module/rdd-combat.js b/module/rdd-combat.js index 80e85b56..bf3d3e38 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -1084,7 +1084,7 @@ export class RdDCombat { } async defenseV2(attackerRoll, callbacks = []) { - // this._prepareParade(attackerRoll, arme, competence); + await this.doRollDefense({ ids: { actorId: this.defender.id, diff --git a/module/roll/chat-roll-result.mjs b/module/roll/chat-roll-result.mjs index 14512801..02e02540 100644 --- a/module/roll/chat-roll-result.mjs +++ b/module/roll/chat-roll-result.mjs @@ -162,12 +162,18 @@ export default class ChatRollResult { return undefined } + getActiveActor(roll) { + return roll.active?.actor ?? (roll.ids?.actorId ? game.actors.get(roll.ids.actorId) : undefined) + } + async saveChatMessageRoll(chatMessage, savedRoll) { await ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll) } loadChatMessageRoll(chatMessage) { - return ChatUtility.getMessageData(chatMessage, 'rollData') + const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') + RollBasicParts.restore(savedRoll) + return savedRoll } async updateChatMessage(chatMessage, savedRoll) { @@ -184,7 +190,7 @@ export default class ChatRollResult { event.preventDefault() const chatMessage = ChatUtility.getChatMessage(event) const savedRoll = this.loadChatMessageRoll(chatMessage) - const actor = game.actors.get(savedRoll.ids.actorId) + const actor = this.getActiveActor(savedRoll) Misc.doIfOwner(actor, it => it.rollAppelChance( () => this.onAppelChanceSuccess(savedRoll, chatMessage), () => this.onAppelChanceEchec(savedRoll, chatMessage)) @@ -193,7 +199,6 @@ export default class ChatRollResult { async onAppelChanceSuccess(savedRoll, chatMessage) { const reRoll = foundry.utils.duplicate(savedRoll) - console.log('onAppelChanceSuccess savedRoll', savedRoll) reRoll.type.retry = true await this.updateChatMessage(chatMessage, reRoll) const callbacks = [ChatUtility.remover(chatMessage)] @@ -222,7 +227,7 @@ export default class ChatRollResult { const chatMessage = ChatUtility.getChatMessage(event) const savedRoll = this.loadChatMessageRoll(chatMessage) - const actor = game.actors.get(savedRoll.ids.actorId) + const actor = this.getActiveActor(savedRoll) Misc.doIfOwner(actor, it => it.appelDestinee(async () => { const reRoll = foundry.utils.duplicate(savedRoll) @@ -235,36 +240,41 @@ 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, - [ChatUtility.remover(chatMessage)] - ) + const actor = this.getActiveActor(savedRoll) + Misc.doIfOwner(actor, it => { + const attackerRoll = savedRoll.attackerRoll + RollDialog.loadRollData(attackerRoll) + this.getCombat(attackerRoll)?.defenseV2(attackerRoll, + [ChatUtility.remover(chatMessage)] + ) + }) } async onClickDefensePossession(event) { const chatMessage = ChatUtility.getChatMessage(event) const savedRoll = this.loadChatMessageRoll(chatMessage) - await RdDPossessionV2.rollDefensePossession(savedRoll, chatMessage) + const actor = this.getActiveActor(savedRoll) + Misc.doIfOwner(actor, it => 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)() + const actor = this.getActiveActor(savedRoll) + Misc.doIfOwner(actor, async it => { + await RdDPossessionV2.onMarquerPointPossession(savedRoll) + ChatUtility.remover(chatMessage)() + }) } async onClickEncaissement(event) { const chatMessage = ChatUtility.getChatMessage(event) const isMessageDemande = ChatUtility.getMessageData(chatMessage, 'demande-defense') const savedRoll = this.loadChatMessageRoll(chatMessage) - const attaque = savedRoll.attackerRoll - const defenderToken = savedRoll.ids.actorTokenId ? canvas.tokens.get(savedRoll.ids.actorTokenId) : undefined - const defender = defenderToken?.actor ?? game.actors.get(savedRoll.ids.actorId) - Misc.doIfOwner(defender, async defender => { + const actor = this.getActiveActor(savedRoll) + Misc.doIfOwner(actor, async defender => { + const defenderToken = savedRoll.active.token + const attaque = savedRoll.attackerRoll const attackerToken = savedRoll.ids.opponentTokenId ? canvas.tokens.get(savedRoll.ids.opponentTokenId) : undefined const attacker = attackerToken?.actor ?? game.actors.get(savedRoll.ids.opponentId) switch (attaque.dmg.mortalite) { @@ -290,9 +300,8 @@ export default class ChatRollResult { async onClickRecul(event) { const chatMessage = ChatUtility.getChatMessage(event) const savedRoll = this.loadChatMessageRoll(chatMessage) - // TODO: gestion sur token non liés? - const defender = game.actors.get(savedRoll.ids.actorId) - Misc.doIfOwner(defender, async defender => { + const actor = this.getActiveActor(savedRoll) + Misc.doIfOwner(actor, async defender => { const attacker = game.actors.get(savedRoll.ids.opponentId) savedRoll.done.recul = await defender.encaisserRecul(attacker.getForce(), savedRoll.attackerRoll.dmg.dmgArme) await this.updateChatMessage(chatMessage, savedRoll) @@ -303,42 +312,54 @@ export default class ChatRollResult { const choix = event.currentTarget.attributes['data-particuliere'].value const chatMessage = ChatUtility.getChatMessage(event) const savedRoll = this.loadChatMessageRoll(chatMessage) - savedRoll.particuliere = choix - savedRoll.particulieres = [RDD_CONFIG.particuliere[choix]] - await this.updateChatMessage(chatMessage, savedRoll) - await this.getCombat(savedRoll)?.onAttaqueV2(savedRoll) + const actor = this.getActiveActor(savedRoll) + Misc.doIfOwner(actor, async it => { + savedRoll.particuliere = choix + savedRoll.particulieres = [RDD_CONFIG.particuliere[choix]] + await this.updateChatMessage(chatMessage, savedRoll) + await this.getCombat(savedRoll)?.onAttaqueV2(savedRoll) + }) } async onClickFaireGouter(event) { const chatMessage = ChatUtility.getChatMessage(event) const savedRoll = this.loadChatMessageRoll(chatMessage) - if (!savedRoll.type.retry) { - savedRoll.type.retry = true - await this.updateChatMessage(chatMessage, savedRoll) - } - await new RollTypeCuisine().onFaireGouter(savedRoll) + const actor = this.getActiveActor(savedRoll) + Misc.doIfOwner(actor, async it => { + if (!savedRoll.type.retry) { + savedRoll.type.retry = true + await this.updateChatMessage(chatMessage, savedRoll) + } + await new RollTypeCuisine().onFaireGouter(savedRoll) + }) } async onClickApprecier(event) { const chatMessage = ChatUtility.getChatMessage(event) const savedRoll = this.loadChatMessageRoll(chatMessage) - await Apprecier.onClickApprecier(savedRoll) + Apprecier.onClickApprecier(savedRoll) } async onClickMonteeTMR(event, mode) { const chatMessage = ChatUtility.getChatMessage(event) const savedRoll = this.loadChatMessageRoll(chatMessage) - if (await new RollTypeMeditation().onMonteeTMR(savedRoll, mode)) { - savedRoll.done.meditation = true - await this.updateChatMessage(chatMessage, savedRoll) - } + const actor = this.getActiveActor(savedRoll) + Misc.doIfOwner(actor, async it => { + if (await new RollTypeMeditation().onMonteeTMR(savedRoll, mode)) { + savedRoll.done.meditation = true + await this.updateChatMessage(chatMessage, savedRoll) + } + }) } async onClickTirerMaladresse(event) { const chatMessage = ChatUtility.getChatMessage(event) const typeMaladresse = event.currentTarget.attributes['data-maladresse'].value const savedRoll = this.loadChatMessageRoll(chatMessage) - savedRoll.maladresse = await RdDRollTables.getMaladresse({ arme: typeMaladresse == 'avec-arme', toChat: false }) - savedRoll.type.retry = true - await this.updateChatMessage(chatMessage, savedRoll) + const actor = this.getActiveActor(savedRoll) + Misc.doIfOwner(actor, async it => { + savedRoll.maladresse = await RdDRollTables.getMaladresse({ arme: typeMaladresse == 'avec-arme', toChat: false }) + savedRoll.type.retry = true + await this.updateChatMessage(chatMessage, savedRoll) + }) } } From 4f4e00b29839f4e5b27fe6df6d237523e43889ce Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Wed, 10 Dec 2025 02:46:22 +0100 Subject: [PATCH 05/26] Ajout: Information de distance --- changelog.md | 3 ++ module/combat/distance.mjs | 63 ++++++++++++++++++++++++++++ module/rdd-combat.js | 59 ++++---------------------- module/roll/roll-part-attaque.mjs | 35 ++++++++++++---- templates/roll/roll-part-attaque.hbs | 17 +++++++- 5 files changed, 117 insertions(+), 60 deletions(-) create mode 100644 module/combat/distance.mjs diff --git a/changelog.md b/changelog.md index 1f66fea5..188dfc23 100644 --- a/changelog.md +++ b/changelog.md @@ -5,9 +5,12 @@ - Corrections diverses - l'encombrement total est affiché avec deux décimales - le poids des monnaies est de nouveau décimal +- Fenêtre de jets V2 + - affichage des ajustements dans la fenêtre d'attaque avec arme à distance - Corrections liées à Foundry v12/v13 - Fix ajout de notes dans le journal par un joueur (/chrono, ou clic sur le libelé de l'heure dans l'horloge) + ## 13.0.21 - La folie d'Illysis - Jets d'appréciation et de moral diff --git a/module/combat/distance.mjs b/module/combat/distance.mjs new file mode 100644 index 00000000..d14fe761 --- /dev/null +++ b/module/combat/distance.mjs @@ -0,0 +1,63 @@ +import { Misc } from "../misc.js" + +export class Distance { + + static ajustements(token, defenderToken, arme){ + const distance = Distance.distance(token, defenderToken) + const isVisible = Distance.isVisible(token, defenderToken) + const portee = Distance.ajustementPortee(distance, arme) + const taille = Distance.ajustementTaille(defenderToken.actor) + const activite = Distance.ajustementMouvement(defenderToken) + const total = Distance.diff(portee, taille, activite) + return { + isVisible: isVisible, + distance: distance, + portee: portee, + taille: taille, + activite: activite, + total: total + } + } + + static distance(token, defenderToken) { + const ray = new foundry.canvas.geometry.Ray( + token.getCenterPoint(), + defenderToken.getCenterPoint() + ) + return Number(canvas.grid.measureDistances([{ ray }], { gridSpaces: false })) + } + + static isVisible(token, defenderToken) { + // TODO: regarder les StatusEffect aveuglé? + return canvas.effects.visibility.testVisibility(defenderToken.getCenterPoint(), { object: token }) + } + + static ajustementPortee(distance, arme) { + if (arme.system.portee_courte && distance <= arme.system.portee_courte) return { msg: "courte", diff: 0 }; + if (arme.system.portee_moyenne && distance <= arme.system.portee_moyenne) return { msg: "moyenne", diff: -3 }; + if (arme.system.portee_extreme && distance <= arme.system.portee_extreme) return { msg: "extrême", diff: -5 }; + return { msg: "inatteignable", diff: -10 }; + } + + static ajustementTaille(actor) { + if (actor.isVehicule()) return { msg: "véhicule", diff: 0 } + const taille = actor.getCaracByName('TAILLE')?.value ?? 1; + if (taille <= 1) return { msg: "souris", diff: -8 }; + if (taille <= 3) return { msg: "chat", diff: -4 }; + if (taille <= 5) return { msg: "chien", diff: -2 }; + if (taille <= 15) return { msg: "humanoïde", diff: 0 }; + if (taille <= 20) return { msg: "ogre", diff: 2 }; + return { msg: "gigantesque", diff: 4 }; + } + + static ajustementMouvement(defenderToken) { + if (defenderToken.actor?.getSurprise(true) != '') return { msg: "immobile (surprise)", diff: 0 }; + if (defenderToken.inCombat) return { msg: "en mouvement (combat)", diff: -4 }; + return { msg: "à déterminer (0 immobile, -3 actif, -4 en mouvement, -5 en zig-zag)", diff: -3 }; + } + + static diff(...ajustements){ + return ajustements.map(it => it.diff).filter(d => !Number.isNaN(d)).reduce(Misc.sum(), 0) + } + +} \ No newline at end of file diff --git a/module/rdd-combat.js b/module/rdd-combat.js index bf3d3e38..1c7f6bbe 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -19,6 +19,7 @@ import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll/roll-constants.mjs" import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js"; import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs"; import { RollBasicParts } from "./roll/roll-basic-parts.mjs"; +import { Distance } from "./combat/distance.mjs"; /* -------------------------------------------- */ const premierRoundInit = [ @@ -625,63 +626,22 @@ export class RdDCombat { } else { const defenderToken = canvas.tokens.get(this.defenderTokenId) - const dist = this.distance(_token, defenderToken) - const isVisible = this.isVisible(_token, defenderToken) - const portee = this._ajustementPortee(dist, rollData.arme) - const taille = this._ajustementTaille(this.defender) - const activite = this._ajustementMouvement(this.defender) - const total = [portee, taille, activite].map(it => it.diff).filter(d => !Number.isNaN(d)).reduce(Misc.sum(), 0) - ChatMessage.create({ - content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-info-distance.hbs', { + const info = foundry.utils.mergeObject( + { rollData: rollData, attacker: _token, - isVisible: isVisible, defender: defenderToken, - distance: dist, - portee: portee, - taille: taille, - activite: activite, - total: total - }), + }, + Distance.ajustements(_token, defenderToken, rollData.arme) + ) + ChatMessage.create({ + content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-info-distance.hbs', info), whisper: ChatUtility.getGMs() }) } } } - isVisible(token, defenderToken) { - return canvas.effects.visibility.testVisibility(defenderToken.center, { object: token }) - } - - distance(token, defenderToken) { - return Number(canvas.grid.measureDistances([{ ray: new Ray(token.center, defenderToken.center) }], { gridSpaces: false })).toFixed(1); - } - - _ajustementPortee(dist, arme) { - if (dist <= arme.system.portee_courte) return { msg: "courte", diff: 0 }; - if (dist <= arme.system.portee_moyenne) return { msg: "moyenne", diff: -3 }; - if (dist <= arme.system.portee_extreme) return { msg: "extrême", diff: -5 }; - return { msg: "inatteignable", diff: -10 }; - } - - _ajustementTaille(actor) { - if (actor.isVehicule()) return { msg: "véhicule", diff: 0 } - const taille = actor.getCaracByName('TAILLE')?.value ?? 1; - if (taille <= 1) return { msg: "souris", diff: -8 }; - if (taille <= 3) return { msg: "chat", diff: -4 }; - if (taille <= 5) return { msg: "chien", diff: -2 }; - if (taille <= 15) return { msg: "humanoïde", diff: 0 }; - if (taille <= 20) return { msg: "ogre", diff: 2 }; - return { msg: "gigantesque", diff: 4 }; - } - - _ajustementMouvement(defender) { - if (defender.getSurprise(true) != '') return { msg: "immobile (surprise)", diff: 0 }; - if (game.combat?.combatants.find(it => it.actorId == defender.id)) return { msg: "en mouvement (combat)", diff: -4 }; - return { msg: "à déterminer (0 immobile, -3 actif, -4 en mouvement, -5 en zig-zag)", diff: -3 }; - } - - async attaqueV2() { if (!await this.attacker.accorder(this.defender, 'avant-attaque')) { return @@ -699,7 +659,6 @@ export class RdDCombat { } async doRollAttaque(rollData, callbacks = []) { - // TODO V2 await this.proposerAjustementTirLancer(rollData) return await RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose, callbacks: [ @@ -740,7 +699,7 @@ export class RdDCombat { } _socketSendMessageDefenseV2(paramChatDefense) { - game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_defense_v2", data: {paramChatDefense} }) + game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_defense_v2", data: { paramChatDefense } }) } static async onMsgDefenseV2(msg) { diff --git a/module/roll/roll-part-attaque.mjs b/module/roll/roll-part-attaque.mjs index 40cd8924..ca3dab78 100644 --- a/module/roll/roll-part-attaque.mjs +++ b/module/roll/roll-part-attaque.mjs @@ -1,3 +1,4 @@ +import { Distance } from "../combat/distance.mjs" import { RDD_CONFIG } from "../constants.js" import { ATTAQUE_TYPE_MELEE } from "../item/arme.js" import { RdDBonus } from "../rdd-bonus.js" @@ -30,7 +31,7 @@ export class RollPartAttaque extends RollPartSelect { loadRefs(rollData) { const refs = this.getRefs(rollData) const attaques = rollData.active.actor.listAttaques() - refs.all = attaques.map(it => RollPartAttaque.$extractAttaque(it, rollData.active.actor)) + refs.all = attaques.map(it => RollPartAttaque.$extractAttaque(it, rollData)) this.filterAttaquesEmpoignade(rollData) refs.tactiques = TACTIQUES if (refs.attaques.length > 0) { @@ -64,13 +65,22 @@ export class RollPartAttaque extends RollPartSelect { choices(refs) { return refs.attaques } - static $extractAttaque(attaque, actor) { + static $extractAttaque(attaque, rollData) { attaque.key = `${attaque.action}::${attaque.label}` attaque.tactique = TACTIQUES[0] attaque.initialDiff = attaque.comp?.system.default_diffLibre ?? 0 + if (RollPartAttaque.isAttaqueDistance(attaque)) { + attaque.distance = Distance.ajustements(rollData.active.token, + rollData.opponent.token, + attaque.arme) + } return attaque } + static isAttaqueDistance(attaque) { + return ['(lancer)', '(tir)'].includes(attaque.main) + } + prepareContext(rollData) { this.filterAttaquesEmpoignade(rollData) const current = this.getCurrent(rollData) @@ -102,20 +112,22 @@ export class RollPartAttaque extends RollPartSelect { } async _onRender(rollDialog, context, options) { + const inputDiff = rollDialog.element.querySelector(`roll-section[name="diff"] input[name="diff"]`) const selectAttaque = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-attaque"]`) const selectTactique = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-tactique"]`) const checkMortalite = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="check-mortalite"]`) const utiliserDagueEmpoignade = rollDialog.element.querySelector(`roll-section[name="${this.code}"] a.utiliser-dague-empoignade`) - const current = this.getCurrent(rollDialog.rollData) + const rollData = rollDialog.rollData + const current = this.getCurrent(rollData) - selectAttaque.addEventListener("change", e => { + selectAttaque?.addEventListener("change", e => { const selectOptions = e.currentTarget.options const index = selectOptions.selectedIndex - this.$selectAttaque(rollDialog.rollData, selectOptions[index]?.value) + this.$selectAttaque(rollData, selectOptions[index]?.value) rollDialog.render() }) - selectTactique.addEventListener("change", e => { + selectTactique?.addEventListener("change", e => { const selectOptions = e.currentTarget.options const index = selectOptions.selectedIndex current.tactique = RdDBonus.find(selectOptions[index]?.value) @@ -128,9 +140,11 @@ export class RollPartAttaque extends RollPartSelect { }) utiliserDagueEmpoignade?.addEventListener("click", e => { e.preventDefault() - const rollData = rollDialog.rollData this.utiliserDagueEmpoignade(rollData) }) + inputDiff?.addEventListener("input", e => { + this.getRefs(rollData).all.forEach(attaque => attaque.initialDiff = undefined) + }) } utiliserDagueEmpoignade(rollData) { @@ -153,8 +167,11 @@ export class RollPartAttaque extends RollPartSelect { case PART_CARAC: return part.filterCaracs(rollData, [current.carac.key]) case PART_COMP: return part.filterComps(rollData, [current.comp.name]) case PART_DIFF: { - if (current.initialDiff) { - part.setDiff(rollData, { type: DIFF.ATTAQUE, value: current.initialDiff }) + if (RollPartAttaque.isAttaqueDistance(current)) { + part.setDiff(rollData, { type: DIFF.DEFAUT }) + } + else { + part.setDiff(rollData, { type: DIFF.ATTAQUE, diff: current.initialDiff }) current.initialDiff = undefined } break diff --git a/templates/roll/roll-part-attaque.hbs b/templates/roll/roll-part-attaque.hbs index 2b1bf3e9..26658bae 100644 --- a/templates/roll/roll-part-attaque.hbs +++ b/templates/roll/roll-part-attaque.hbs @@ -63,7 +63,22 @@ {{/if}} + {{#if current.distance}} - + + Attaque à distance {{current.main}} proposé de {{current.distance.total}} à valider par le Gardien + + +
    +
  • La cible est à une distance indicative de {{numberFormat current.distance.distance decimals=1}} mètres.
  • +
  • Avec les murs et la lumière, la cible + {{#if current.distance.isVisible}}est{{else}}n'est pas{{/if}} visible. +
  • +
  • Portée {{current.distance.portee.msg}} : {{current.distance.portee.diff}}
  • +
  • De taille {{current.distance.taille.msg}}: {{current.distance.taille.diff}}
  • +
  • Mouvement {{current.distance.activite.msg}}: {{current.distance.activite.diff}}
  • +
+
+ {{/if}} \ No newline at end of file From 30090872d4d41af392209dce659e8a8fc57366ea Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 11 Dec 2025 03:12:31 +0100 Subject: [PATCH 06/26] =?UTF-8?q?Gestion=20d=C3=A9fense=20=C3=A0=20distanc?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- changelog.md | 1 + module/actor.js | 7 ++- module/combat/distance.mjs | 67 +++++++++++++++++++++++----- module/item-competence.js | 2 +- module/item-competencecreature.js | 7 +-- module/item-sheet.js | 2 +- module/rdd-combat.js | 2 +- module/roll/roll-part-attaque.mjs | 12 +---- module/roll/roll-part-defense.mjs | 58 +++++++++++++++--------- templates/chat-demande-defense.hbs | 4 +- templates/roll/roll-part-attaque.hbs | 2 +- templates/roll/roll-part-defense.hbs | 23 ++++++++-- 12 files changed, 129 insertions(+), 58 deletions(-) diff --git a/changelog.md b/changelog.md index 188dfc23..8a743128 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,7 @@ - le poids des monnaies est de nouveau décimal - Fenêtre de jets V2 - affichage des ajustements dans la fenêtre d'attaque avec arme à distance + - gestion des défenses contre les armes à distance - Corrections liées à Foundry v12/v13 - Fix ajout de notes dans le journal par un joueur (/chrono, ou clic sur le libelé de l'heure dans l'horloge) diff --git a/module/actor.js b/module/actor.js index 4718f936..8e468536 100644 --- a/module/actor.js +++ b/module/actor.js @@ -54,6 +54,7 @@ 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 { Apprecier, MORAL, SITUATION_MORAL } from "./moral/apprecier.mjs"; +import { Distance } from "./combat/distance.mjs"; export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre'] @@ -205,7 +206,7 @@ export class RdDActor extends RdDBaseActorSang { const niveau = comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(main) ? -8 : -6) const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + ecaillesEfficacite - actions.push({ + const attaque = { label: arme.name + (main ? ' ' + main : ''), action: 'attaque', initOnly: false, @@ -217,7 +218,9 @@ export class RdDActor extends RdDBaseActorSang { dommages: dommages, forceRequise: forceRequise, initiative: RdDInitiative.getRollInitiative(caracValue, niveau, ajustement) - }) + }; + attaque.isDistance = Distance.typeAttaqueDistance(attaque), + actions.push(attaque) } addAttaque(RdDItemArme.empoignade(this), ATTAQUE_TYPE.CORPS_A_CORPS) diff --git a/module/combat/distance.mjs b/module/combat/distance.mjs index d14fe761..0131fb15 100644 --- a/module/combat/distance.mjs +++ b/module/combat/distance.mjs @@ -1,22 +1,39 @@ +import { ITEM_TYPES } from "../constants.js" +import { Grammar } from "../grammar.js" +import { ATTAQUE_TYPE } from "../item/arme.js" import { Misc } from "../misc.js" export class Distance { - static ajustements(token, defenderToken, arme){ + static typeAttaqueDistance(attaque) { + function mapTypeAttaque(value) { + switch (value) { + case ATTAQUE_TYPE.LANCER: case 'lancer': return ATTAQUE_TYPE.LANCER + case ATTAQUE_TYPE.TIR: case 'tir': return ATTAQUE_TYPE.TIR + } + return undefined + } + switch (attaque.comp.type) { + case ITEM_TYPES.competence: return mapTypeAttaque(attaque.main) + case ITEM_TYPES.competencecreature: return mapTypeAttaque(attaque.arme.system.categorie) + } + return undefined + } + + static ajustements(token, defenderToken, attaque) { + const typeAttaque = Distance.typeAttaqueDistance(attaque) + if (typeAttaque) { + const distance = Distance.distance(token, defenderToken) const isVisible = Distance.isVisible(token, defenderToken) - const portee = Distance.ajustementPortee(distance, arme) + const portee = Distance.ajustementPortee(distance, attaque.arme) const taille = Distance.ajustementTaille(defenderToken.actor) const activite = Distance.ajustementMouvement(defenderToken) const total = Distance.diff(portee, taille, activite) - return { - isVisible: isVisible, - distance: distance, - portee: portee, - taille: taille, - activite: activite, - total: total - } + const diffDefense = Distance.ajustementDefense(attaque) + return { typeAttaque, isVisible, distance, portee, taille, activite, total, diffDefense } + } + return undefined } static distance(token, defenderToken) { @@ -56,8 +73,34 @@ export class Distance { return { msg: "à déterminer (0 immobile, -3 actif, -4 en mouvement, -5 en zig-zag)", diff: -3 }; } - static diff(...ajustements){ - return ajustements.map(it => it.diff).filter(d => !Number.isNaN(d)).reduce(Misc.sum(), 0) + static diff(...ajustements) { + return ajustements.map(it => it.diff).filter(d => !Number.isNaN(d)).reduce(Misc.sum(), 0) + } + + static ajustementDefense(attaque) { + switch (Grammar.toLowerCaseNoAccentNoSpace(attaque.comp.name)) { + case 'arbalete': return { label: 'Parade carreau', value: -5 } + case 'arc': return { label: 'Parade flêche', value: -5 } + case 'fronde': return { label: 'Parade bille de fronde', value: -4 } + case 'daguedejet': return { label: 'Parade/Esquive dague lancée', value: -2 } + case 'javelot': return { label: 'Parade/Esquive javelot lancé', value: -2 } + case 'fouet': return { label: 'Parade/Esquive fouet', value: 0 } + } + return { label: 'Parade/esquive projectile', value: 0 } + } + + static ajustementBouclier(bouclier) { + if (bouclier?.system.categorie_parade == 'boucliers') { + if (bouclier.system.force < 10) { + return { label: 'Bouclier léger', value: -3 } + } + if (bouclier.system.force < 12) { + return { label: 'Bouclier moyen', value: 0 } + } + return { label: 'Bouclier lourd', value: 3 } + } + /* esquive */ + return undefined } } \ No newline at end of file diff --git a/module/item-competence.js b/module/item-competence.js index 764ce7f1..2e755a1b 100644 --- a/module/item-competence.js +++ b/module/item-competence.js @@ -2,7 +2,7 @@ import { Grammar } from "./grammar.js"; import { RdDInitiative } from "./initiative.mjs"; import { RdDItem } from "./item.js"; -import { CATEGORIES_COMPETENCE_COMBAT, CATEGORIES_COMPETENCES, SANS_COMPETENCE } from "./item/base-items.js"; +import { CATEGORIES_COMPETENCES, SANS_COMPETENCE } from "./item/base-items.js"; import { Misc } from "./misc.js"; const competenceTroncs = [["Esquive", "Dague", "Corps à corps"], diff --git a/module/item-competencecreature.js b/module/item-competencecreature.js index 80b735e6..c8a4fbc5 100644 --- a/module/item-competencecreature.js +++ b/module/item-competencecreature.js @@ -2,6 +2,7 @@ import { ITEM_TYPES } from "./constants.js"; import { RdDItem } from "./item.js"; import { RdDInitiative } from "./initiative.mjs"; import { RdDItemArme } from "./item/arme.js"; +import { Distance } from "./combat/distance.mjs"; /* -------------------------------------------- */ export class RdDItemCompetenceCreature extends RdDItem { @@ -45,12 +46,12 @@ export class RdDItemCompetenceCreature extends RdDItem { equipe: true, mortalite: this.system.mortalite, dommages: this.system.dommages, - //dmg: this.system.dommages, initiative: initative - }; + } + attaque.isDistance = Distance.typeAttaqueDistance(attaque) return attaque } - return undefined; + return undefined } getCategorieAttaque() { diff --git a/module/item-sheet.js b/module/item-sheet.js index b27cc56a..3362c922 100644 --- a/module/item-sheet.js +++ b/module/item-sheet.js @@ -104,7 +104,7 @@ 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: [SANS_COMPETENCE, ...competences], + competences: [new RdDItemCompetence(SANS_COMPETENCE), ...competences], categories: RdDItem.getCategories(this.item.type), isAppreciable: Apprecier.isAppreciable(this.item) } diff --git a/module/rdd-combat.js b/module/rdd-combat.js index 1c7f6bbe..a4467e31 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -632,7 +632,7 @@ export class RdDCombat { attacker: _token, defender: defenderToken, }, - Distance.ajustements(_token, defenderToken, rollData.arme) + Distance.ajustements(_token, defenderToken, { arme: rollData.arme, main: rollData.competence.system.categorie }) ) ChatMessage.create({ content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-info-distance.hbs', info), diff --git a/module/roll/roll-part-attaque.mjs b/module/roll/roll-part-attaque.mjs index ca3dab78..11d39549 100644 --- a/module/roll/roll-part-attaque.mjs +++ b/module/roll/roll-part-attaque.mjs @@ -69,18 +69,10 @@ export class RollPartAttaque extends RollPartSelect { attaque.key = `${attaque.action}::${attaque.label}` attaque.tactique = TACTIQUES[0] attaque.initialDiff = attaque.comp?.system.default_diffLibre ?? 0 - if (RollPartAttaque.isAttaqueDistance(attaque)) { - attaque.distance = Distance.ajustements(rollData.active.token, - rollData.opponent.token, - attaque.arme) - } + attaque.distance = Distance.ajustements(rollData.active.token, rollData.opponent.token, attaque) return attaque } - static isAttaqueDistance(attaque) { - return ['(lancer)', '(tir)'].includes(attaque.main) - } - prepareContext(rollData) { this.filterAttaquesEmpoignade(rollData) const current = this.getCurrent(rollData) @@ -167,7 +159,7 @@ export class RollPartAttaque extends RollPartSelect { case PART_CARAC: return part.filterCaracs(rollData, [current.carac.key]) case PART_COMP: return part.filterComps(rollData, [current.comp.name]) case PART_DIFF: { - if (RollPartAttaque.isAttaqueDistance(current)) { + if (Distance.typeAttaqueDistance(current)) { part.setDiff(rollData, { type: DIFF.DEFAUT }) } else { diff --git a/module/roll/roll-part-defense.mjs b/module/roll/roll-part-defense.mjs index ab13927e..48614d19 100644 --- a/module/roll/roll-part-defense.mjs +++ b/module/roll/roll-part-defense.mjs @@ -1,4 +1,5 @@ -import { ITEM_TYPES, RDD_CONFIG } from "../constants.js" +import { Distance } from "../combat/distance.mjs" +import { ITEM_TYPES } from "../constants.js" import { ATTAQUE_TYPE, RdDItemArme } from "../item/arme.js" import { CARACS } from "../rdd-carac.js" import { DIFF, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs" @@ -19,53 +20,55 @@ export class RollPartDefense extends RollPartSelect { 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? - return attackerRoll.diffLibre; - } - loadRefs(rollData) { const refs = this.getRefs(rollData) const attackerRoll = rollData.attackerRoll const defenseur = rollData.active.actor - refs.isDistance = [ATTAQUE_TYPE.TIR, ATTAQUE_TYPE.LANCER].find(it => it == attackerRoll?.main) + refs.distance = rollData.attackerRoll.current.attaque.distance const isEmpoignade = attackerRoll.dmg.isEmpoignade const isEmpoignadeEnCours = isEmpoignade && defenseur.itemTypes[ITEM_TYPES.empoignade].find(it => [it.system.empoigneurid, it.system.empoigneid].includes(rollData.ids.opponentId) && it.system.pointsemp != 0) - const esquives = (refs.isDistance == ATTAQUE_TYPE.TIR || isEmpoignadeEnCours) + const esquives = (refs.distance?.typeAttaque == ATTAQUE_TYPE.TIR || isEmpoignadeEnCours) ? [] : defenseur.getCompetencesEsquive() const parades = isEmpoignade ? [RdDItemArme.empoignade(defenseur)] - : defenseur.items.filter(it => it.isParade() && (!refs.isDistance || it.isBouclier())) + : defenseur.items.filter(it => it.isParade() && (!refs.distance || it.isBouclier())) refs.defenses = [ - ...esquives.map(it => RollPartDefense.$extractEsquive(it, defenseur)), - ...parades.map(it => RollPartDefense.$extractParade(it, attackerRoll?.arme, defenseur)) + ...esquives.map(it => RollPartDefense.$extractEsquive(it, defenseur, attackerRoll)), + ...parades.map(it => RollPartDefense.$extractParade(it, defenseur, attackerRoll)) ] this.$selectDefense(rollData) } - static $extractEsquive(esquive, defenseur) { - return { + static $extractEsquive(esquive, defenseur, attackerRoll) { + const defense = { key: esquive.id, label: esquive.name, img: esquive.img, - // TODO: carac pour créatures + // TODO: carac pour créatures à vérifier carac: defenseur.isPersonnage() ? CARACS.DEROBEE : esquive.name, verb: "esquive", comp: esquive, isEsquive: true } + if (attackerRoll.current.attaque.distance) { + defense.distance = { + ajustementDefense: Distance.ajustementDefense(attackerRoll.current.attaque), + } + } + return defense } - static $extractParade(armeDefense, armeAttaque, defenseur) { + static $extractParade(armeDefense, defenseur, attackerRoll) { + const armeAttaque = attackerRoll?.arme const comp = (ITEM_TYPES.competencecreature == armeDefense.type) ? armeDefense : defenseur.getCompetence(armeDefense.system.competence) - return { + const defense = { key: armeDefense.id, label: 'Parade ' + armeDefense.name, img: armeDefense.img, @@ -78,6 +81,13 @@ export class RollPartDefense extends RollPartSelect { typeParade: armeAttaque ? RdDItemArme.defenseArmeParade(armeDefense, armeAttaque) : 'norm', isEsquive: false } + if (attackerRoll.current.attaque.distance) { + defense.distance = { + ajustementBouclier: Distance.ajustementBouclier(armeDefense), + ajustementDefense: Distance.ajustementDefense(attackerRoll.current.attaque), + } + } + return defense } prepareContext(rollData) { @@ -107,10 +117,11 @@ export class RollPartDefense extends RollPartSelect { impactOtherPart(part, rollData) { if (this.visible(rollData)) { + const refs = this.getRefs(rollData) const current = this.getCurrent(rollData) switch (part.code) { - case PART_CARAC: return part.filterCaracs(rollData, [current.carac]) - case PART_COMP: return part.filterComps(rollData, [current.comp?.name]) + case PART_CARAC: return part.filterCaracs(rollData, refs.defenses.length > 0 ? [current.carac] : ['impossible']) + case PART_COMP: return part.filterComps(rollData, refs.defenses.length > 0 ? [current.comp?.name] : ['impossible']) case PART_DIFF: return part.setDiff(rollData, this.getDiffDefense(rollData)) case PART_SIGN: return part.setArme(rollData, this.isArmeDisparate(rollData), current.forceRequise) } @@ -129,16 +140,19 @@ export class RollPartDefense extends RollPartSelect { getDiffDefense(rollData) { const refs = this.getRefs(rollData) - if (refs.isDistance || !rollData.attackerRoll) { - // TODO: Déterminer la difficulté de parade - return { diff: 0, type: DIFF.LIBRE } + if (refs.distance) { + const current = this.getCurrent(rollData) + const diff = (current.distance?.ajustementBouclier?.value ?? 0) + + (current.distance?.ajustementDefense?.value ?? 0) + return { diff: diff, type: DIFF.DEFENSE } } - else { + if (rollData.attackerRoll) { const attackerRoll = rollData.attackerRoll const diff = attackerRoll.v2 ? attackerRoll.selected.diff.value : attackerRoll.diff return { diff: diff ?? 0, type: DIFF.DEFENSE } } + return { diff: 0, type: DIFF.LIBRE } } } diff --git a/templates/chat-demande-defense.hbs b/templates/chat-demande-defense.hbs index 28ef4eb6..a62f515f 100644 --- a/templates/chat-demande-defense.hbs +++ b/templates/chat-demande-defense.hbs @@ -31,8 +31,8 @@ Se défendre - {{#if (or (eq attackerRoll.attaqueCategorie 'tir') (eq attackerRoll.attaqueCategorie 'lancer'))}} - (difficulté à déterminer) + {{#if attackerRoll.current.attaque.isDistance}} + (à distance) {{else}} à {{attackerRoll.current.diff.value}} {{/if}} diff --git a/templates/roll/roll-part-attaque.hbs b/templates/roll/roll-part-attaque.hbs index 26658bae..eb5648dd 100644 --- a/templates/roll/roll-part-attaque.hbs +++ b/templates/roll/roll-part-attaque.hbs @@ -66,7 +66,7 @@ {{#if current.distance}} - Attaque à distance {{current.main}} proposé de {{current.distance.total}} à valider par le Gardien + Attaque à distance {{current.main}} difficulté proposée de {{current.distance.total}} à valider par le Gardien diff --git a/templates/roll/roll-part-defense.hbs b/templates/roll/roll-part-defense.hbs index e2d7e59d..0680fb19 100644 --- a/templates/roll/roll-part-defense.hbs +++ b/templates/roll/roll-part-defense.hbs @@ -3,10 +3,27 @@ - + {{#if refs.defenses.length}} + + {{else}} + + Aucune défense disponible {{#if refs.distance}}contre cette attaque à distance {{refs.distance.typeAttaque}}{{/if}} + + {{/if}} + {{#if refs.distance}} + Défense contre une attaque à distance {{refs.distance.typeAttaque}} + {{log 'defense' this}} + {{#if current.distance.ajustementDefense}} + {{current.distance.ajustementDefense.label}}: {{current.distance.ajustementDefense.value}} + {{/if}} + {{#if current.distance.ajustementBouclier}} + {{current.distance.ajustementBouclier.label}}: {{current.distance.ajustementBouclier.value}} + {{/if}} + Activité du défenseur: 0 si immobile et prêt, -3 si actif (à ajouter manuellement aux conditions) + {{/if}} {{#if rollData.active.effets}} From 15ce2588b8028cff9f46073b80190dffa0e34486 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 11 Dec 2025 03:26:38 +0100 Subject: [PATCH 07/26] =?UTF-8?q?Correction=20sur=20d=C3=A9fense?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/roll/roll-dialog.mjs | 15 +++++++++------ module/roll/roll-part-defense.mjs | 6 +++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/module/roll/roll-dialog.mjs b/module/roll/roll-dialog.mjs index 6076d4e9..bbc2c373 100644 --- a/module/roll/roll-dialog.mjs +++ b/module/roll/roll-dialog.mjs @@ -327,6 +327,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 function saveBasics(from, to) { if (from) { + to.ids = from.ids to.passeArme = from.passeArme to.rolled = from.rolled to.particuliere = from.particuliere @@ -337,15 +338,14 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 to.attackerRoll = {} saveBasics(from.attackerRoll, to.attackerRoll) } + if (from.current) { + // stockage de current + ROLL_PARTS.filter(p => p.isActive(from)) + .forEach(p => p.storeClean(from, target)) + } } } - const target = RollBasicParts.initFrom(rollData) - 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 = { @@ -540,6 +540,9 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 static loadRollData(roll) { RollDialog.$prepareRollData(roll) + if (roll.attackerRoll){ + RollDialog.$prepareRollData(roll.attackerRoll) + } RollDialog.calculAjustement(roll) roll.v2 = true return roll diff --git a/module/roll/roll-part-defense.mjs b/module/roll/roll-part-defense.mjs index 48614d19..9221aefc 100644 --- a/module/roll/roll-part-defense.mjs +++ b/module/roll/roll-part-defense.mjs @@ -24,7 +24,7 @@ export class RollPartDefense extends RollPartSelect { const refs = this.getRefs(rollData) const attackerRoll = rollData.attackerRoll const defenseur = rollData.active.actor - refs.distance = rollData.attackerRoll.current.attaque.distance + refs.distance = rollData.attackerRoll.current?.attaque?.distance const isEmpoignade = attackerRoll.dmg.isEmpoignade const isEmpoignadeEnCours = isEmpoignade && defenseur.itemTypes[ITEM_TYPES.empoignade].find(it => [it.system.empoigneurid, it.system.empoigneid].includes(rollData.ids.opponentId) && @@ -55,7 +55,7 @@ export class RollPartDefense extends RollPartSelect { comp: esquive, isEsquive: true } - if (attackerRoll.current.attaque.distance) { + if (attackerRoll.current?.attaque?.distance) { defense.distance = { ajustementDefense: Distance.ajustementDefense(attackerRoll.current.attaque), } @@ -81,7 +81,7 @@ export class RollPartDefense extends RollPartSelect { typeParade: armeAttaque ? RdDItemArme.defenseArmeParade(armeDefense, armeAttaque) : 'norm', isEsquive: false } - if (attackerRoll.current.attaque.distance) { + if (attackerRoll.current?.attaque?.distance) { defense.distance = { ajustementBouclier: Distance.ajustementBouclier(armeDefense), ajustementDefense: Distance.ajustementDefense(attackerRoll.current.attaque), From 3567885030efe03325cd3d3728943e23a5d22caa Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 12 Dec 2025 17:40:27 +0100 Subject: [PATCH 08/26] Police lisible dans les messages de tchat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Résout des problèmes de polices pas toujours cohérentes dans les messages de tchat --- css/foundryvtt-reve-de-dragon.css | 5 +++++ less/fonts.less | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/css/foundryvtt-reve-de-dragon.css b/css/foundryvtt-reve-de-dragon.css index 2fac0925..9297772e 100644 --- a/css/foundryvtt-reve-de-dragon.css +++ b/css/foundryvtt-reve-de-dragon.css @@ -63,6 +63,11 @@ #sidebar { font-family: "GoudyAcc"; } +.sheet header.sheet-header h1 input .chat-message, +.window-app .window-header .chat-message, +#sidebar .chat-message { + font-family: "CaslonAntique"; +} /* For title, sidebar character and scene */ .sheet nav.sheet-tabs, .window-app input, diff --git a/less/fonts.less b/less/fonts.less index 0ca55362..9b6658e1 100644 --- a/less/fonts.less +++ b/less/fonts.less @@ -71,7 +71,11 @@ .sheet header.sheet-header h1 input, .window-app .window-header, #sidebar { - font-family: "GoudyAcc" + font-family: "GoudyAcc"; + + .chat-message{ + font-family: "CaslonAntique"; + } } /* For title, sidebar character and scene */ From 6907344be794bb7a5d2e9d2689fbffec46b2f0e6 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 12 Dec 2025 17:42:43 +0100 Subject: [PATCH 09/26] =?UTF-8?q?R=C3=A9solution=20de=20soucis=20inter-typ?= =?UTF-8?q?es=20de=20jets=20V2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - diminution de la dépendance au token cible pour les attaques - ne pas proposer l'attaque sur les jets "par défaut" - filtrer les sous-parties inutiles (ie: sorts pour les attaques, etc) --- module/combat/distance.mjs | 33 ++++++++++++++------- module/roll/roll-constants.mjs | 3 +- module/roll/roll-dialog-adapter.mjs | 2 +- module/roll/roll-dialog.mjs | 16 ++++++++-- module/roll/roll-part-attaque.mjs | 8 +++-- module/roll/roll-part-cuisine.mjs | 6 ++-- module/roll/roll-part-defense.mjs | 7 +++-- module/roll/roll-part-ecailles.mjs | 8 +++-- module/roll/roll-part-empoignade-taille.mjs | 4 ++- module/roll/roll-part-empoignade.mjs | 4 ++- module/roll/roll-part-jeu.mjs | 5 ++-- module/roll/roll-part-meditation.mjs | 9 +++--- module/roll/roll-part-oeuvre.mjs | 7 +++-- module/roll/roll-part-possession.mjs | 13 ++++---- module/roll/roll-part-sort.mjs | 5 ++-- module/roll/roll-part-tache.mjs | 5 ++-- module/roll/roll-part.mjs | 17 +++-------- 17 files changed, 91 insertions(+), 61 deletions(-) diff --git a/module/combat/distance.mjs b/module/combat/distance.mjs index 0131fb15..0c72cc7c 100644 --- a/module/combat/distance.mjs +++ b/module/combat/distance.mjs @@ -23,11 +23,10 @@ export class Distance { static ajustements(token, defenderToken, attaque) { const typeAttaque = Distance.typeAttaqueDistance(attaque) if (typeAttaque) { - const distance = Distance.distance(token, defenderToken) const isVisible = Distance.isVisible(token, defenderToken) const portee = Distance.ajustementPortee(distance, attaque.arme) - const taille = Distance.ajustementTaille(defenderToken.actor) + const taille = Distance.ajustementTaille(defenderToken?.actor) const activite = Distance.ajustementMouvement(defenderToken) const total = Distance.diff(portee, taille, activite) const diffDefense = Distance.ajustementDefense(attaque) @@ -37,19 +36,28 @@ export class Distance { } static distance(token, defenderToken) { - const ray = new foundry.canvas.geometry.Ray( - token.getCenterPoint(), - defenderToken.getCenterPoint() - ) - return Number(canvas.grid.measureDistances([{ ray }], { gridSpaces: false })) + if (token && defenderToken) { + const ray = new foundry.canvas.geometry.Ray( + token.getCenterPoint(), + defenderToken.getCenterPoint() + ) + return Number(canvas.grid.measureDistances([{ ray }], { gridSpaces: false })) + } + return -1 /* distance indéterminée */ } static isVisible(token, defenderToken) { // TODO: regarder les StatusEffect aveuglé? - return canvas.effects.visibility.testVisibility(defenderToken.getCenterPoint(), { object: token }) + if (token && defenderToken) { + return canvas.effects.visibility.testVisibility(defenderToken.getCenterPoint(), { object: token }) + } + return true } static ajustementPortee(distance, arme) { + if (distance < 0 || !arme) { + return { msg: "non déterminée", diff: 0 }; + } if (arme.system.portee_courte && distance <= arme.system.portee_courte) return { msg: "courte", diff: 0 }; if (arme.system.portee_moyenne && distance <= arme.system.portee_moyenne) return { msg: "moyenne", diff: -3 }; if (arme.system.portee_extreme && distance <= arme.system.portee_extreme) return { msg: "extrême", diff: -5 }; @@ -57,6 +65,9 @@ export class Distance { } static ajustementTaille(actor) { + if (!actor) { + return { msg: "non déterminée", diff: 0 }; + } if (actor.isVehicule()) return { msg: "véhicule", diff: 0 } const taille = actor.getCaracByName('TAILLE')?.value ?? 1; if (taille <= 1) return { msg: "souris", diff: -8 }; @@ -68,8 +79,10 @@ export class Distance { } static ajustementMouvement(defenderToken) { - if (defenderToken.actor?.getSurprise(true) != '') return { msg: "immobile (surprise)", diff: 0 }; - if (defenderToken.inCombat) return { msg: "en mouvement (combat)", diff: -4 }; + if (defenderToken) { + if (defenderToken.actor?.getSurprise(true) != '') return { msg: "immobile (surprise)", diff: 0 }; + if (defenderToken.inCombat) return { msg: "en mouvement (combat)", diff: -4 }; + } return { msg: "à déterminer (0 immobile, -3 actif, -4 en mouvement, -5 en zig-zag)", diff: -3 }; } diff --git a/module/roll/roll-constants.mjs b/module/roll/roll-constants.mjs index 4e2103af..ac77d16f 100644 --- a/module/roll/roll-constants.mjs +++ b/module/roll/roll-constants.mjs @@ -13,8 +13,7 @@ export const ROLL_TYPE_TACHE = 'tache' export const ATTAQUE_ROLL_TYPES = [ROLL_TYPE_ATTAQUE] export const COMBAT_ROLL_TYPES = [ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE] export const DEMIREVE_ROLL_TYPES = [ROLL_TYPE_SORT] -export const DEFAULT_ROLL_TYPES = [ROLL_TYPE_COMP, ROLL_TYPE_ATTAQUE, ROLL_TYPE_TACHE, ROLL_TYPE_MEDITATION, ROLL_TYPE_CUISINE, ROLL_TYPE_OEUVRE, ROLL_TYPE_JEU] - +export const DEFAULT_ROLL_TYPES = [ROLL_TYPE_COMP, ROLL_TYPE_TACHE, ROLL_TYPE_MEDITATION, ROLL_TYPE_CUISINE, ROLL_TYPE_OEUVRE, ROLL_TYPE_JEU] export const DIFF = { LIBRE: 'libre', diff --git a/module/roll/roll-dialog-adapter.mjs b/module/roll/roll-dialog-adapter.mjs index 21c7c0b4..b81e7bdf 100644 --- a/module/roll/roll-dialog-adapter.mjs +++ b/module/roll/roll-dialog-adapter.mjs @@ -50,7 +50,7 @@ export class RollDialogAdapter { rolled.factorHtml = Misc.getFractionOneN(rollData.current.sign.diviseur) if (ReglesOptionnelles.isUsing("afficher-colonnes-reussite")) { rolled.niveauNecessaire = RdDResolutionTable.findNiveauNecessaire(rolled.caracValue, rolled.roll) - rolled.ajustementNecessaire = rolled.niveauNecessaire - diff + rolled.ajustementNecessaire = rolled.niveauNecessaire - rolled.finalLevel } return rolled } diff --git a/module/roll/roll-dialog.mjs b/module/roll/roll-dialog.mjs index bbc2c373..d57af4f7 100644 --- a/module/roll/roll-dialog.mjs +++ b/module/roll/roll-dialog.mjs @@ -310,8 +310,10 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 rollData.refs = foundry.utils.mergeObject(rollData.refs ?? {}, Object.fromEntries(ROLL_PARTS.map(p => [p.code, {}]))); rollData.options = rollData.options ?? { rollMode: game.settings.get("core", "rollMode") } - ROLL_PARTS.forEach(p => p.initialize(rollData)) - ROLL_PARTS.filter(p => p.isValid(rollData)) + ROLL_PARTS.forEach(p => RollDialog.$initializeRollPart(rollData, p.code)) + ROLL_PARTS + .filter(p => RollDialog.$isIntersecting(allowed, p.rollTypes)) + .filter(p => p.isValid(rollData)) .forEach(p => { p.restore(rollData) p.loadRefs(rollData) @@ -320,6 +322,14 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 return rollData } + static $initializeRollPart(rollData, code) { + rollData.refs[code] = rollData.refs[code] ?? {} + rollData.current[code] = rollData.current[code] ?? {} + rollData.selected[code] = rollData.selected[code] ?? {} + } + + static $isIntersecting(allowed, included) { return included ? included.find(it => allowed.includes(it)) : true } + static saveParts(rollData, impacts = undefined) { if (rollData == undefined) { return undefined @@ -540,7 +550,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 static loadRollData(roll) { RollDialog.$prepareRollData(roll) - if (roll.attackerRoll){ + if (roll.attackerRoll) { RollDialog.$prepareRollData(roll.attackerRoll) } RollDialog.calculAjustement(roll) diff --git a/module/roll/roll-part-attaque.mjs b/module/roll/roll-part-attaque.mjs index 11d39549..8c869f3a 100644 --- a/module/roll/roll-part-attaque.mjs +++ b/module/roll/roll-part-attaque.mjs @@ -11,7 +11,7 @@ import { PART_COMP } from "./roll-part-comp.mjs" import { PART_DIFF } from "./roll-part-diff.mjs" import { RollPartSelect } from "./roll-part-select.mjs" import { PART_SIGN } from "./roll-part-sign.mjs" -import { ROLLDIALOG_SECTION } from "./roll-part.mjs" +import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" export const PART_ATTAQUE = 'attaque' @@ -26,7 +26,9 @@ export class RollPartAttaque extends RollPartSelect { get code() { return PART_ATTAQUE } get section() { return ROLLDIALOG_SECTION.CHOIX } - visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_ATTAQUE) } + get rollTypes() { return [ROLL_TYPE_ATTAQUE] } + + visible(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_ATTAQUE) } loadRefs(rollData) { const refs = this.getRefs(rollData) @@ -69,7 +71,7 @@ export class RollPartAttaque extends RollPartSelect { attaque.key = `${attaque.action}::${attaque.label}` attaque.tactique = TACTIQUES[0] attaque.initialDiff = attaque.comp?.system.default_diffLibre ?? 0 - attaque.distance = Distance.ajustements(rollData.active.token, rollData.opponent.token, attaque) + attaque.distance = Distance.ajustements(rollData.active?.token, rollData.opponent?.token, attaque) return attaque } diff --git a/module/roll/roll-part-cuisine.mjs b/module/roll/roll-part-cuisine.mjs index cedfaef9..17e33c63 100644 --- a/module/roll/roll-part-cuisine.mjs +++ b/module/roll/roll-part-cuisine.mjs @@ -4,7 +4,7 @@ import { ROLL_TYPE_CUISINE } 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" +import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" export const PART_CUISINE = "cuisine" @@ -16,8 +16,10 @@ export class RollPartCuisine extends RollPartSelect { get code() { return PART_CUISINE } get section() { return ROLLDIALOG_SECTION.CHOIX } + get rollTypes() { return [ROLL_TYPE_CUISINE] } + isValid(rollData) { return rollData.active.actor.isPersonnage() } - visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_CUISINE) } + visible(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_CUISINE) } restore(rollData) { super.restore(rollData) diff --git a/module/roll/roll-part-defense.mjs b/module/roll/roll-part-defense.mjs index 9221aefc..5add0f61 100644 --- a/module/roll/roll-part-defense.mjs +++ b/module/roll/roll-part-defense.mjs @@ -8,7 +8,7 @@ import { PART_COMP } from "./roll-part-comp.mjs" import { PART_DIFF } from "./roll-part-diff.mjs" import { RollPartSelect } from "./roll-part-select.mjs" import { PART_SIGN } from "./roll-part-sign.mjs" -import { ROLLDIALOG_SECTION } from "./roll-part.mjs" +import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" export const PART_DEFENSE = 'defense' @@ -17,8 +17,9 @@ export class RollPartDefense extends RollPartSelect { get code() { return PART_DEFENSE } get section() { return ROLLDIALOG_SECTION.CHOIX } - isValid(rollData) { return this.isRollType(rollData, ROLL_TYPE_DEFENSE) && rollData.attackerRoll != undefined } - visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_DEFENSE) && rollData.attackerRoll != undefined } + get rollTypes() { return [ROLL_TYPE_DEFENSE] } + isValid(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_DEFENSE) && rollData.attackerRoll != undefined } + visible(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_DEFENSE) && rollData.attackerRoll != undefined } loadRefs(rollData) { const refs = this.getRefs(rollData) diff --git a/module/roll/roll-part-ecailles.mjs b/module/roll/roll-part-ecailles.mjs index af09a27d..99659bbf 100644 --- a/module/roll/roll-part-ecailles.mjs +++ b/module/roll/roll-part-ecailles.mjs @@ -3,6 +3,7 @@ import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs" import { PART_ATTAQUE } from "./roll-part-attaque.mjs" import { RollPartCheckbox } from "./roll-part-checkbox.mjs" import { PART_DEFENSE } from "./roll-part-defense.mjs" +import { RollPart } from "./roll-part.mjs" const ECAILLES = "ecailles" @@ -10,8 +11,9 @@ export class RollPartEcailles extends RollPartCheckbox { get code() { return ECAILLES } + get rollTypes() { return [ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE] } isValid(rollData) { - return this.isRollType(rollData, ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE) + return RollPart.isRollType(rollData, ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE) } visible(rollData) { @@ -25,9 +27,9 @@ export class RollPartEcailles extends RollPartCheckbox { } getArme(rollData) { - return this.isRollType(rollData, ROLL_TYPE_ATTAQUE) + return RollPart.isRollType(rollData, ROLL_TYPE_ATTAQUE) ? rollData.current[PART_ATTAQUE]?.arme - : this.isRollType(rollData, ROLL_TYPE_DEFENSE) + : RollPart.isRollType(rollData, ROLL_TYPE_DEFENSE) ? rollData.current[PART_DEFENSE]?.arme : undefined } diff --git a/module/roll/roll-part-empoignade-taille.mjs b/module/roll/roll-part-empoignade-taille.mjs index 80779522..bebce150 100644 --- a/module/roll/roll-part-empoignade-taille.mjs +++ b/module/roll/roll-part-empoignade-taille.mjs @@ -1,7 +1,8 @@ import { RDD_CONFIG } from "../constants.js" import { RdDEmpoignade } from "../rdd-empoignade.js" -import { COMBAT_ROLL_TYPES } from "./roll-constants.mjs" +import { COMBAT_ROLL_TYPES, ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs" import { RollPartCheckbox } from "./roll-part-checkbox.mjs" +import { RollPart } from "./roll-part.mjs" const EMPOIGNADE_TAILLE = "empoignade-taille" @@ -9,6 +10,7 @@ export class RollPartEmpoignadeTaille extends RollPartCheckbox { get code() { return EMPOIGNADE_TAILLE } + get rollTypes() { return [ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE] } isValid(rollData) { return RdDEmpoignade.isCombatantEmpoignade(rollData.ids.actorId, rollData.ids.actorTokenId) } diff --git a/module/roll/roll-part-empoignade.mjs b/module/roll/roll-part-empoignade.mjs index fd7a5f0f..f0cf4827 100644 --- a/module/roll/roll-part-empoignade.mjs +++ b/module/roll/roll-part-empoignade.mjs @@ -1,9 +1,10 @@ import { RDD_CONFIG } from "../constants.js" import { ATTAQUE_TYPE_MELEE } from "../item/arme.js" import { RdDEmpoignade } from "../rdd-empoignade.js" -import { ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs" +import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs" import { PART_ATTAQUE } from "./roll-part-attaque.mjs" import { RollPartCheckbox } from "./roll-part-checkbox.mjs" +import { RollPart } from "./roll-part.mjs" const EMPOIGNADE = "empoignade" @@ -11,6 +12,7 @@ export class RollPartEmpoignade extends RollPartCheckbox { get code() { return EMPOIGNADE } + get rollTypes() { return [ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE] } isValid(rollData) { return RdDEmpoignade.isCombatantEmpoignade(rollData.ids.opponentId, rollData.ids.opponentTokenId) && !RdDEmpoignade.isCombatantEmpoignade(rollData.ids.actorId, rollData.ids.actorTokenId) diff --git a/module/roll/roll-part-jeu.mjs b/module/roll/roll-part-jeu.mjs index f20d13b5..4f711dec 100644 --- a/module/roll/roll-part-jeu.mjs +++ b/module/roll/roll-part-jeu.mjs @@ -4,7 +4,7 @@ import { ROLL_TYPE_JEU } from "./roll-constants.mjs" import { PART_CARAC } from "./roll-part-carac.mjs" import { PART_COMP, RollPartComp } from "./roll-part-comp.mjs" import { RollPartSelect } from "./roll-part-select.mjs" -import { ROLLDIALOG_SECTION } from "./roll-part.mjs" +import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" import { RdDItem } from "../item.js" import { Misc } from "../misc.js" @@ -17,8 +17,9 @@ export class RollPartJeu extends RollPartSelect { get code() { return PART_JEU } get section() { return ROLLDIALOG_SECTION.CHOIX } + get rollTypes() { return [ROLL_TYPE_JEU] } isValid(rollData) { return rollData.active.actor.isPersonnage() } - visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_JEU) } + visible(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_JEU) } loadRefs(rollData) { const refs = this.getRefs(rollData) diff --git a/module/roll/roll-part-meditation.mjs b/module/roll/roll-part-meditation.mjs index 6c93f33d..ee707003 100644 --- a/module/roll/roll-part-meditation.mjs +++ b/module/roll/roll-part-meditation.mjs @@ -7,7 +7,7 @@ import { ROLL_TYPE_MEDITATION } from "./roll-constants.mjs" import { PART_CARAC, RollPartCarac } 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" +import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" export const PART_MEDITATION = "meditation" @@ -18,6 +18,10 @@ export class RollPartMeditation extends RollPartSelect { get code() { return PART_MEDITATION } get section() { return ROLLDIALOG_SECTION.CHOIX } + get rollTypes() { return [ROLL_TYPE_MEDITATION] } + isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() } + visible(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_MEDITATION) } + store(rollData, targetData) { const current = this.getCurrent(rollData) this.setSaved(targetData, { @@ -29,9 +33,6 @@ export class RollPartMeditation extends RollPartSelect { }) } - isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() } - visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_MEDITATION) } - loadRefs(rollData) { const refs = this.getRefs(rollData) const actor = rollData.active.actor diff --git a/module/roll/roll-part-oeuvre.mjs b/module/roll/roll-part-oeuvre.mjs index a8dd637a..bbe19943 100644 --- a/module/roll/roll-part-oeuvre.mjs +++ b/module/roll/roll-part-oeuvre.mjs @@ -5,7 +5,7 @@ import { ROLL_TYPE_OEUVRE } 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" +import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" export const PART_OEUVRE = "oeuvre" @@ -35,8 +35,9 @@ export class RollPartOeuvre extends RollPartSelect { get code() { return PART_OEUVRE } get section() { return ROLLDIALOG_SECTION.CHOIX } + get rollTypes() { return [ROLL_TYPE_OEUVRE] } isValid(rollData) { return rollData.active.actor.isPersonnage() } - visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_OEUVRE) } + visible(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_OEUVRE) } loadRefs(rollData) { const refs = this.getRefs(rollData) @@ -88,7 +89,7 @@ export class RollPartOeuvre extends RollPartSelect { const current = this.getCurrent(rollData) switch (part.code) { case PART_CARAC: return part.filterCaracs(rollData, current.caracs) - case PART_COMP: return part.filterComps(rollData,[current.comp?.name]) + case PART_COMP: return part.filterComps(rollData, [current.comp?.name]) } } return undefined diff --git a/module/roll/roll-part-possession.mjs b/module/roll/roll-part-possession.mjs index 7e146ddd..6e3ae905 100644 --- a/module/roll/roll-part-possession.mjs +++ b/module/roll/roll-part-possession.mjs @@ -5,7 +5,7 @@ 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" +import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" export const PART_POSSESSION = "possession" @@ -17,7 +17,8 @@ export class RollPartPossession extends RollPartSelect { get name() { return 'Possession' } get section() { return ROLLDIALOG_SECTION.CHOIX } - visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_POSSESSION) } + get rollTypes() { return [ROLL_TYPE_POSSESSION] } + visible(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_POSSESSION) } loadRefs(rollData) { const refs = this.getRefs(rollData) @@ -61,10 +62,10 @@ export class RollPartPossession extends RollPartSelect { rollDialog.render() }) button?.addEventListener("click", async e => { - e.preventDefault() - await RdDPossessionV2.createPossessionIfMissing(rollData.active, rollData.opponent) - rollDialog.render() - }) + e.preventDefault() + await RdDPossessionV2.createPossessionIfMissing(rollData.active, rollData.opponent) + rollDialog.render() + }) } $selectPossession(rollData, key) { diff --git a/module/roll/roll-part-sort.mjs b/module/roll/roll-part-sort.mjs index 182f7e79..97e3c5ea 100644 --- a/module/roll/roll-part-sort.mjs +++ b/module/roll/roll-part-sort.mjs @@ -2,7 +2,7 @@ import { ITEM_TYPES } from "../constants.js" import { ROLL_TYPE_SORT } from "./roll-constants.mjs" import { PART_CARAC } from "./roll-part-carac.mjs" import { PART_COMP } from "./roll-part-comp.mjs" -import { ROLLDIALOG_SECTION } from "./roll-part.mjs" +import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" import { TMRUtility } from "../tmr-utility.js" import { RdDItemSort } from "../item-sort.js" import { RollPartSelect } from "./roll-part-select.mjs" @@ -19,8 +19,9 @@ export class RollPartSort extends RollPartSelect { get code() { return PART_SORT } get section() { return ROLLDIALOG_SECTION.CHOIX } + get rollTypes() { return [ROLL_TYPE_SORT] } isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() } - visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_SORT) } + visible(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_SORT) } restore(rollData) { const saved = this.getSaved(rollData) diff --git a/module/roll/roll-part-tache.mjs b/module/roll/roll-part-tache.mjs index cfde3f82..bd8fcd97 100644 --- a/module/roll/roll-part-tache.mjs +++ b/module/roll/roll-part-tache.mjs @@ -3,7 +3,7 @@ import { ROLL_TYPE_TACHE } 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" +import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" export const PART_TACHE = "tache" @@ -12,8 +12,9 @@ export class RollPartTache extends RollPartSelect { get code() { return PART_TACHE } get section() { return ROLLDIALOG_SECTION.CHOIX } + get rollTypes() { return [ROLL_TYPE_TACHE] } isValid(rollData) { return rollData.active.actor.isPersonnage() } - visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_TACHE) } + visible(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_TACHE) } loadRefs(rollData) { const refs = this.getRefs(rollData) diff --git a/module/roll/roll-part.mjs b/module/roll/roll-part.mjs index a76611eb..bd4c30d9 100644 --- a/module/roll/roll-part.mjs +++ b/module/roll/roll-part.mjs @@ -1,3 +1,5 @@ +import { ALL_ROLL_TYPES } from "./roll-dialog.mjs" + export const ROLLDIALOG_SECTION = { ACTION: 'action', CARAC: 'carac', @@ -19,17 +21,6 @@ export class RollPart { /** le template handlebars pour affichage */ get template() { return `systems/foundryvtt-reve-de-dragon/templates/roll/roll-part-${this.code}.hbs` } - initialize(rollData) { - if (rollData.refs[this.code] == undefined) { - rollData.refs[this.code] = {} - } - if (rollData.current[this.code] == undefined) { - rollData.current[this.code] = {} - } - if (rollData.selected[this.code] == undefined) { - rollData.selected[this.code] = {} - } - } /** l'acteur actif du jet */ getActor(rollData) { return rollData.active.actor } /** le conteneur de données du RollPart */ @@ -78,8 +69,8 @@ export class RollPart { * @returns une chaîne vide si rien ne doit être affiché */ title() { return '' } - isRollType(rollData, ...type) { return type.includes(rollData.type.current)} - + static isRollType(rollData, ...type) { return type.includes(rollData.type.current) } + get rollTypes() { return undefined } isActive(rollData) { return this.isValid(rollData) && this.visible(rollData) } isValid(rollData) { return true } visible(rollData) { return true } From b939d9bebff3bf3fb7cb5db1b73eab051b653d44 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 12 Dec 2025 17:58:01 +0100 Subject: [PATCH 10/26] =?UTF-8?q?Correction=20affichage=20colonnes=20r?= =?UTF-8?q?=C3=A9ussite?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit affichage des colonnes de réussite/ajustement nécessaire --- module/roll/roll-dialog-adapter.mjs | 4 ---- templates/roll/result/partial-infojet.hbs | 5 +++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/module/roll/roll-dialog-adapter.mjs b/module/roll/roll-dialog-adapter.mjs index b81e7bdf..1f620f1d 100644 --- a/module/roll/roll-dialog-adapter.mjs +++ b/module/roll/roll-dialog-adapter.mjs @@ -92,10 +92,6 @@ export class RollDialogAdapter { if (rollData.current[PART_APPELMORAL]?.checked) { rollData.use.moral = true } - if (ReglesOptionnelles.isUsing("afficher-colonnes-reussite")) { - rolled.niveauNecessaire = RdDResolutionTable.findNiveauNecessaire(rollData.selectedCarac.value, rolled.roll) - rolled.ajustementNecessaire = rolled.niveauNecessaire - diff - } rollData.ajustements = rollData.ajustements.map(a => { return { label: a.label, value: a.value } }) } diff --git a/templates/roll/result/partial-infojet.hbs b/templates/roll/result/partial-infojet.hbs index 18992ba5..316d27e0 100644 --- a/templates/roll/result/partial-infojet.hbs +++ b/templates/roll/result/partial-infojet.hbs @@ -26,7 +26,8 @@ {{/if}}
{{rolled.roll}} : {{rolled.quality}} - {{#if rolled.ajustementNecessaire}} - (Réussite si {{plusMoins rolled.niveauNecessaire}} / avec niveau {{plusMoins rolled.ajustementNecessaire}}) + {{log 'rolled' rolled}} + {{#if (regle-optionnelle 'afficher-colonnes-reussite')}} + (Réussite colonne {{plusMoins rolled.niveauNecessaire}} / avec ajustement {{plusMoins rolled.ajustementNecessaire}}) {{/if}}
\ No newline at end of file From 2912b5ce9bc8c27d214c13fe5b6375b16410adce Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 12 Dec 2025 23:31:33 +0100 Subject: [PATCH 11/26] Fix possession - defense --- changelog.md | 1 + module/rdd-possession-v2.mjs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 8a743128..290bface 100644 --- a/changelog.md +++ b/changelog.md @@ -8,6 +8,7 @@ - Fenêtre de jets V2 - affichage des ajustements dans la fenêtre d'attaque avec arme à distance - gestion des défenses contre les armes à distance + - défense contre possession - Corrections liées à Foundry v12/v13 - Fix ajout de notes dans le journal par un joueur (/chrono, ou clic sur le libelé de l'heure dans l'horloge) diff --git a/module/rdd-possession-v2.mjs b/module/rdd-possession-v2.mjs index b1594dad..bd83ab11 100644 --- a/module/rdd-possession-v2.mjs +++ b/module/rdd-possession-v2.mjs @@ -178,7 +178,7 @@ export class RdDPossessionV2 { static async onRollDefense(defense) { if (defense.rolled.isEchec) { - await RdDPossessionV2.addPointPossession(defense.opponent.actor, defense.active.actor) + await RdDPossessionV2.addPointPossession(defense.opponent, defense.active) } RdDPossessionV2.resetPossession(defense) } From 95747929637949f0fdf31eae69a22f9105b67f9e Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 12 Dec 2025 23:38:28 +0100 Subject: [PATCH 12/26] =?UTF-8?q?Icones=20pour=20acteurs=20et=20sc=C3=A8ne?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/ui/icon_sidebar_actor.svg | 450 +------------------------------ assets/ui/icon_sidebar_scene.svg | 450 +------------------------------ changelog.md | 2 + 3 files changed, 4 insertions(+), 898 deletions(-) diff --git a/assets/ui/icon_sidebar_actor.svg b/assets/ui/icon_sidebar_actor.svg index 86087bae..c4c12951 100644 --- a/assets/ui/icon_sidebar_actor.svg +++ b/assets/ui/icon_sidebar_actor.svg @@ -1,449 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/ui/icon_sidebar_scene.svg b/assets/ui/icon_sidebar_scene.svg index 6d171138..78e899ad 100644 --- a/assets/ui/icon_sidebar_scene.svg +++ b/assets/ui/icon_sidebar_scene.svg @@ -1,449 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/changelog.md b/changelog.md index 290bface..8f76e056 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,8 @@ ## 13.0.22 - Les reflets d'Illysis +- Améliorations + - Changements d'icones pour les Acteurs et Scènes - Corrections diverses - l'encombrement total est affiché avec deux décimales - le poids des monnaies est de nouveau décimal From 2c7fd32ae6a87289ec64a1d8f8afc6e5d7ceb67e Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 12 Dec 2025 23:31:04 +0100 Subject: [PATCH 13/26] Fix typo --- changelog.md | 1 + module/rdd-combat.js | 2 +- .../personnage_le_Cuisinier_Haut_R_vant_X9d5McdSAT1Ivp39.yml | 2 +- .../personnage_le_Haut_R_vant_Dilettante_4bI9HX4oomMEXrOT.yml | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 8f76e056..169ce39b 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,7 @@ - Corrections diverses - l'encombrement total est affiché avec deux décimales - le poids des monnaies est de nouveau décimal + - Erreurs de typographie diverses - Fenêtre de jets V2 - affichage des ajustements dans la fenêtre d'attaque avec arme à distance - gestion des défenses contre les armes à distance diff --git a/module/rdd-combat.js b/module/rdd-combat.js index a4467e31..8bfe4dfb 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -154,7 +154,7 @@ export class RdDCombatManager extends Combat { alias: combatant.token?.name, sound: CONFIG.sounds.dice, }, - flavor: `${combatant.token?.name} a une initiatyive de ${init.value} : ${messageOptions.info}
` + flavor: `${combatant.token?.name} a une initiative de ${init.value} : ${messageOptions.info}
` }, messageOptions); init.roll.toMessage(messageData, { rollMode, create: true }); diff --git a/packs_src/voyageurs/personnage_le_Cuisinier_Haut_R_vant_X9d5McdSAT1Ivp39.yml b/packs_src/voyageurs/personnage_le_Cuisinier_Haut_R_vant_X9d5McdSAT1Ivp39.yml index 4cf35f3c..08cd61d8 100644 --- a/packs_src/voyageurs/personnage_le_Cuisinier_Haut_R_vant_X9d5McdSAT1Ivp39.yml +++ b/packs_src/voyageurs/personnage_le_Cuisinier_Haut_R_vant_X9d5McdSAT1Ivp39.yml @@ -3344,7 +3344,7 @@ items: - _id: yQ5mkpLoQH0g9g5P name: Huile type: munition - img: systems/foundryvtt-reve-de-dragon/icons/liquides/liquide__neutre.webp + img: systems/foundryvtt-reve-de-dragon/icons/liquides/liquide_neutre.webp effects: [] folder: null sort: 300001 diff --git a/packs_src/voyageurs/personnage_le_Haut_R_vant_Dilettante_4bI9HX4oomMEXrOT.yml b/packs_src/voyageurs/personnage_le_Haut_R_vant_Dilettante_4bI9HX4oomMEXrOT.yml index 41e6bad5..4fa15e49 100644 --- a/packs_src/voyageurs/personnage_le_Haut_R_vant_Dilettante_4bI9HX4oomMEXrOT.yml +++ b/packs_src/voyageurs/personnage_le_Haut_R_vant_Dilettante_4bI9HX4oomMEXrOT.yml @@ -3634,7 +3634,7 @@ items: name: Décoction de méritoine type: munition sort: 300001 - img: systems/foundryvtt-reve-de-dragon/icons/liquides/liquide__neutre.webp + img: systems/foundryvtt-reve-de-dragon/icons/liquides/liquide_neutre.webp effects: [] system: description:

1 mesure (20cl) de décoction de Méritoine.

From 7ea1f36852e1848ae1ad9d854dce4da64b88e64b Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 13 Dec 2025 00:00:17 +0100 Subject: [PATCH 14/26] =?UTF-8?q?Corrections=20mise=20sort=20en=20r=C3=A9s?= =?UTF-8?q?erve?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La mise en réserve de sorts depuis la feuille de personne ne marchait pas à cause de rêve variables --- changelog.md | 1 + module/actor.js | 3 ++- module/item-sort.js | 5 +++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 169ce39b..17b2d48f 100644 --- a/changelog.md +++ b/changelog.md @@ -8,6 +8,7 @@ - l'encombrement total est affiché avec deux décimales - le poids des monnaies est de nouveau décimal - Erreurs de typographie diverses + - Mise en réserve de sort par le Gardien - Fenêtre de jets V2 - affichage des ajustements dans la fenêtre d'attaque avec arme à distance - gestion des défenses contre les armes à distance diff --git a/module/actor.js b/module/actor.js index 8e468536..1af87fa2 100644 --- a/module/actor.js +++ b/module/actor.js @@ -1092,12 +1092,13 @@ export class RdDActor extends RdDBaseActorSang { } $createSortReserve(sort) { + const ptReve = Number.isInteger(sort.system.ptreve) ? Number(sort.system.ptreve) :Number(sort.system.ptreve.match(/\d+/)) this.createEmbeddedDocuments("Item", [{ type: ITEM_TYPES.sortreserve, name: sort.name, img: sort.img, - system: { sortid: sort.id, draconic: sort.system.draconic, ptreve: Number(sort.system.ptreve.match(/\d+/)), coord: 'A1', heurecible: 'Vaisseau' } + system: { sortid: sort.id, draconic: sort.system.draconic, ptreve: ptReve, coord: 'A1', heurecible: 'Vaisseau' } }], { renderSheet: true }) } diff --git a/module/item-sort.js b/module/item-sort.js index 196253c0..c0b948e0 100644 --- a/module/item-sort.js +++ b/module/item-sort.js @@ -3,6 +3,7 @@ import { RdDItemCompetence } from "./item-competence.js"; import { ITEM_TYPES } from "./constants.js"; import { Misc } from "./misc.js"; import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js"; +import { RdDItem } from "./item.js"; export const VOIES_DRACONIC = [ { code: 'O', label: "Voie d'Oniros", short: 'Oniros', ordre: 'a' }, @@ -14,7 +15,7 @@ export const VOIES_DRACONIC = [ ] /* -------------------------------------------- */ -export class RdDItemSort extends Item { +export class RdDItemSort extends RdDItem { static preloadHandlebars() { Handlebars.registerHelper('itemSort-codeDraconic', voie => RdDItemSort.getCode(voie)) Handlebars.registerHelper('itemSort-shortDraconic', voie => RdDItemSort.getShortVoie(voie)) @@ -62,7 +63,7 @@ export class RdDItemSort extends Item { static diffReve(sort) { return RdDItemSort.toVar((sort.system.difficulte.match(/\-?(\d)+/) ? 'R' : 'R ') + sort.system.difficulte) } - static coutReve(sort) { return RdDItemSort.toVar((Number.isInteger(sort.system.ptreve || sort.system.ptreve.match(/(\d)+\+?/)) ? 'r' : 'r ') + sort.system.ptreve) } + static coutReve(sort) { return RdDItemSort.toVar((Number.isInteger(sort.system.ptreve) || sort.system.ptreve.match(/(\d)+\+?/) ? 'r' : 'r ') + sort.system.ptreve) } static getDraconicsSort(competencesDraconic, sort) { // se baser sur la voie du sort? switch (Grammar.toLowerCaseNoAccent(sort.name)) { From 8077656ea18bd1f0d76c70c4156d66e3c114d727 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 13 Dec 2025 00:06:09 +0100 Subject: [PATCH 15/26] =?UTF-8?q?Fix=20erreurs=20dans=20console=20sur=20fe?= =?UTF-8?q?n=C3=AAtre=20TMR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ajout de mécanismes de sécurité pour éviter erreur rare (liée à un état étrange après avoir été dans les TMR) --- module/rdd-tmr-dialog.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js index 1303882a..652359a8 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -13,7 +13,6 @@ import { Draconique } from "./tmr/draconique.js"; import { HtmlUtility } from "./html-utility.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { RdDDice } from "./rdd-dice.js"; -import { STATUSES } from "./settings/status-effects.js"; import { RdDRencontre } from "./item/rencontre.js"; import { ITEM_TYPES } from "./constants.js"; import { Misc } from "./misc.js"; @@ -187,7 +186,9 @@ export class RdDTMRDialog extends Dialog { async restoreTMRAfterAction() { this.subdialog = undefined await this.maximize() - this.bringToFront() + if (this.rendered) { + this.bringToFront() + } } forceTMRContinueAction() { @@ -348,10 +349,10 @@ export class RdDTMRDialog extends Dialog { return false } this.descenteTMR = true - await await this.actor.quitterTMR(message, this.viewOnly, this.cumulFatigue) - this.pixiTMR.close(); + await await this.actor?.quitterTMR(message, this.viewOnly, this.cumulFatigue) + this.pixiTMR?.close() this.pixiTMR = undefined - await super.close(); + await super.close() return true } From a4e614860a69a325e894e2e8a45da2411f1654a6 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 13 Dec 2025 00:34:10 +0100 Subject: [PATCH 16/26] =?UTF-8?q?Fix:=20aucune=20m=C3=A9ditation=20connue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cas de haut-rêvant ne connaissant pas de méditations --- changelog.md | 1 + module/roll/roll-part-meditation.mjs | 18 ++++++++++-------- module/roll/roll-type-meditation.mjs | 4 ++-- module/time/rdd-timestamp.js | 4 ++-- templates/roll/roll-part-meditation.hbs | 6 ++++++ 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/changelog.md b/changelog.md index 17b2d48f..98c45cc4 100644 --- a/changelog.md +++ b/changelog.md @@ -13,6 +13,7 @@ - affichage des ajustements dans la fenêtre d'attaque avec arme à distance - gestion des défenses contre les armes à distance - défense contre possession + - correction du mode "méditation" quand le haut-rêvant ne connait pas de méditation - Corrections liées à Foundry v12/v13 - Fix ajout de notes dans le journal par un joueur (/chrono, ou clic sur le libelé de l'heure dans l'horloge) diff --git a/module/roll/roll-part-meditation.mjs b/module/roll/roll-part-meditation.mjs index ee707003..1a14be8d 100644 --- a/module/roll/roll-part-meditation.mjs +++ b/module/roll/roll-part-meditation.mjs @@ -4,7 +4,7 @@ import { CARACS } from "../rdd-carac.js" import { RdDTimestamp } from "../time/rdd-timestamp.js" import { TMRUtility } from "../tmr-utility.js" import { ROLL_TYPE_MEDITATION } from "./roll-constants.mjs" -import { PART_CARAC, RollPartCarac } from "./roll-part-carac.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, RollPart } from "./roll-part.mjs" @@ -70,7 +70,7 @@ export class RollPartMeditation extends RollPartSelect { } getMalusEchecs(rollData) { - return this.getCurrent(rollData).meditation.system.malus + return this.getCurrent(rollData).meditation?.system.malus ?? 0 } getAjustements(rollData) { @@ -90,16 +90,18 @@ export class RollPartMeditation extends RollPartSelect { $selectConditionMeditation(rollData) { const current = this.getCurrent(rollData) - current.heureMonde = RdDTimestamp.getWorldTime().heure - current.heureMeditation = RdDTimestamp.findHeure(current.meditation.system.heure)?.heure - current.isHeure = current.heureMeditation == current.heureMonde - current.isTMR = Grammar.equalsInsensitive(current.meditation.system.tmr, TMRUtility.getTMRType(rollData.active.actor.system.reve.tmrpos.coord)) + if (current.meditation){ + current.heureMonde = RdDTimestamp.getWorldTime().heure + current.heureMeditation = RdDTimestamp.findHeure(current.meditation.system.heure)?.heure + current.isHeure = current.heureMeditation == current.heureMonde + current.isTMR = Grammar.equalsInsensitive(current.meditation.system.tmr, TMRUtility.getTMRType(rollData.active.actor.system.reve.tmrpos.coord)) + } } async _onRender(rollDialog, context, options) { const selectMeditation = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-meditation"]`) - selectMeditation.addEventListener("change", e => { + selectMeditation?.addEventListener("change", e => { const selectOptions = e.currentTarget.options const index = selectOptions.selectedIndex this.$selectMeditation(rollDialog.rollData, selectOptions[index]?.value) @@ -111,7 +113,7 @@ export class RollPartMeditation extends RollPartSelect { setupListenerCondition(rollDialog, inputName) { const checkbox = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${inputName}"]`) - checkbox.addEventListener("change", e => { + checkbox?.addEventListener("change", e => { const current = this.getCurrent(rollDialog.rollData) current[inputName] = e.currentTarget.checked rollDialog.render() diff --git a/module/roll/roll-type-meditation.mjs b/module/roll/roll-type-meditation.mjs index c3238487..7d0f6879 100644 --- a/module/roll/roll-type-meditation.mjs +++ b/module/roll/roll-type-meditation.mjs @@ -11,7 +11,7 @@ export class RollTypeMeditation extends RollType { visible(rollData) { return rollData.active.actor.isHautRevant() } title(rollData) { const current = rollData.current[PART_MEDITATION] - const theme = current?.meditation.system.theme + const theme = current?.meditation?.system.theme return theme ? 'médite sur ' + theme : 'médite' } @@ -23,7 +23,7 @@ export class RollTypeMeditation extends RollType { static async $onRollMeditation(rollData) { const actor = rollData.active.actor - const meditation = rollData.current.meditation.meditation + const meditation = rollData.current.meditation?.meditation const rolled = rollData.rolled if (meditation && rolled) { if (rolled.isSuccess) { diff --git a/module/time/rdd-timestamp.js b/module/time/rdd-timestamp.js index bdf4107a..3353af37 100644 --- a/module/time/rdd-timestamp.js +++ b/module/time/rdd-timestamp.js @@ -173,10 +173,10 @@ export class RdDTimestamp { } filtered = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label).includes(heure)); if (filtered.length > 0) { - filtered.sort(Misc.ascending(h => h.label.length)); + filtered.sort(Misc.ascending(h => h.label.length)) return filtered[0] } - return undefined; + return undefined } /** diff --git a/templates/roll/roll-part-meditation.hbs b/templates/roll/roll-part-meditation.hbs index f9be4cbf..e842058b 100644 --- a/templates/roll/roll-part-meditation.hbs +++ b/templates/roll/roll-part-meditation.hbs @@ -2,6 +2,7 @@ +{{#if refs.meditations}} Rêve actuel: {{rollData.active.actor.system.reve.reve.value}} @@ -71,4 +72,9 @@ {{current.meditation.system.veture}}
+ {{else}} + +

Le haut-rêvant ne connait aucune méditation

+
+ {{/if}}
From 97cb730ab5b377ee1d96f4ae6f5db02568de5c4a Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 13 Dec 2025 00:48:31 +0100 Subject: [PATCH 17/26] Fix: aucun jeu connu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La fenêtre de jet se comporte correctement si le personnage ne sait pas jouer, --- changelog.md | 1 + module/roll/roll-part-jeu.mjs | 10 ++++++++-- templates/roll/roll-part-jeu.hbs | 6 ++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 98c45cc4..ebbbd8eb 100644 --- a/changelog.md +++ b/changelog.md @@ -14,6 +14,7 @@ - gestion des défenses contre les armes à distance - défense contre possession - correction du mode "méditation" quand le haut-rêvant ne connait pas de méditation + - correction du mode "jeu" quand le personnage ne connait pas de jeux - Corrections liées à Foundry v12/v13 - Fix ajout de notes dans le journal par un joueur (/chrono, ou clic sur le libelé de l'heure dans l'horloge) diff --git a/module/roll/roll-part-jeu.mjs b/module/roll/roll-part-jeu.mjs index 4f711dec..7405c6b5 100644 --- a/module/roll/roll-part-jeu.mjs +++ b/module/roll/roll-part-jeu.mjs @@ -7,6 +7,7 @@ import { RollPartSelect } from "./roll-part-select.mjs" import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" import { RdDItem } from "../item.js" import { Misc } from "../misc.js" +import { Grammar } from "../grammar.js" export const PART_JEU = "jeu" @@ -89,14 +90,19 @@ export class RollPartJeu extends RollPartSelect { static forceCompJeu(rollData) { const jeu = rollData.current[PART_JEU].base ?? rollData.current[PART_JEU].comp - rollData.refs[PART_COMP].comps = [jeu].map(it => RollPartComp.extractComp(it)) + if (jeu){ + rollData.refs[PART_COMP].comps = [jeu].map(it => RollPartComp.extractComp(it)) + } + else { + rollData.refs[PART_COMP].comps = rollData.refs[PART_COMP].all.filter(comp => comp.label == 'Jeu') + } rollData.current[PART_COMP] = rollData.refs[PART_COMP].comps[0] } async _onRender(rollDialog, context, options) { const selectjeu = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-jeu"]`) - selectjeu.addEventListener("change", e => { + selectjeu?.addEventListener("change", e => { const selectOptions = e.currentTarget.options const index = selectOptions.selectedIndex this.$selectJeu(rollDialog.rollData, selectOptions[index]?.value) diff --git a/templates/roll/roll-part-jeu.hbs b/templates/roll/roll-part-jeu.hbs index 4e32398a..79cb87ac 100644 --- a/templates/roll/roll-part-jeu.hbs +++ b/templates/roll/roll-part-jeu.hbs @@ -2,6 +2,7 @@ + {{#if refs.jeux}} - {{selectOptions refs.oeuvres selected=current.key valueAttr="key" labelAttr="label"}} - + {{#if refs.oeuvres}} + + + {{#if current.oeuvre}} + {{plusMoins current.value}} + {{/if}} + {{#if current.oeuvre}} - {{plusMoins current.value}} + {{> (concat 'roll-oeuvre-' current.oeuvre.type)}} {{/if}} - - {{#if current.oeuvre}} - {{> (concat 'roll-oeuvre-' current.oeuvre.type)}} + {{else}} + +

Le personnage ne connait aucune œuvre à interpréter

+
{{/if}}
\ No newline at end of file From 2894905fc6039e9b580e74a774060d3185d89369 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 13 Dec 2025 02:04:27 +0100 Subject: [PATCH 19/26] =?UTF-8?q?Fen=C3=AAtre=20de=20jet=20V2=20pour=20jet?= =?UTF-8?q?=20quelconque?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- changelog.md | 1 + module/actor/base-actor-reve.js | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/changelog.md b/changelog.md index 5114d0dd..134c249b 100644 --- a/changelog.md +++ b/changelog.md @@ -10,6 +10,7 @@ - Erreurs de typographie diverses - Mise en réserve de sort par le Gardien - Fenêtre de jets V2 + - utilisation pour les jets quelconques - affichage des ajustements dans la fenêtre d'attaque avec arme à distance - gestion des défenses contre les armes à distance - défense contre possession diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index cedfb66e..3322692e 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -385,6 +385,19 @@ export class RdDBaseActorReve extends RdDBaseActor { /* -------------------------------------------- */ async roll() { + if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) { + const rollData = { + ids: { actorId: this.id }, + type: { + allowed: DEFAULT_ROLL_TYPES, + current: PART_COMP, + }, + selected: { + diff: { type: DIFF.DEFAUT } + } + } + return await RollDialog.create(rollData) + } RdDEmpoignade.checkEmpoignadeEnCours(this) const carac = this.getCarac() From 31764e01188ff244b3c1abfe6665cb853866c361 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 13 Dec 2025 02:05:46 +0100 Subject: [PATCH 20/26] =?UTF-8?q?Fermeture=20de=20la=20fen=C3=AAtre=20de?= =?UTF-8?q?=20jet=20depuis=20un=20lien?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- changelog.md | 1 + module/actor.js | 2 +- module/apps/textroll/text-roll-carac-competence.js | 7 +++++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 134c249b..10cf4147 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,7 @@ - Mise en réserve de sort par le Gardien - Fenêtre de jets V2 - utilisation pour les jets quelconques + - la fenêtre de jet pour les jets depuis un lien texte - affichage des ajustements dans la fenêtre d'attaque avec arme à distance - gestion des défenses contre les armes à distance - défense contre possession diff --git a/module/actor.js b/module/actor.js index 1af87fa2..dfa0ed74 100644 --- a/module/actor.js +++ b/module/actor.js @@ -1954,7 +1954,7 @@ export class RdDActor extends RdDBaseActorSang { diff: { value: diff ?? 0 } } } - return await RollDialog.create(rollData) + return await RollDialog.create(rollData, options) } RdDEmpoignade.checkEmpoignadeEnCours(this) diff --git a/module/apps/textroll/text-roll-carac-competence.js b/module/apps/textroll/text-roll-carac-competence.js index 4fe0d8e8..da78fdc9 100644 --- a/module/apps/textroll/text-roll-carac-competence.js +++ b/module/apps/textroll/text-roll-carac-competence.js @@ -3,6 +3,8 @@ import { RdDCarac } from "../../rdd-carac.js"; import { RdDItemCompetence } from "../../item-competence.js"; import { RdDUtility } from "../../rdd-utility.js"; import { TextRollManager } from "./text-roll-formatter.js"; +import RollDialog from "../../roll/roll-dialog.mjs"; +import { OptionsAvancees, ROLL_DIALOG_V2 } from "../../settings/options-avancees.js"; const REGECP_CARAC = "(?[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+)" const REGEXP_COMP = "(\\/(?[A-Za-zÀ-ÖØ-öø-ÿ ]+([1-2]?[A-Za-zÀ-ÖØ-öø-ÿ ]+)?))?" @@ -49,10 +51,11 @@ export class TextRollCaracCompetence { caracCode = actor.mapCarac(caracCode) if (caracCode) { if (competence) { - await actor.rollCaracCompetence(caracCode, competence, diff) + await actor.rollCaracCompetence(caracCode, competence, diff, + { title: "", onRollDone: RollDialog.onRollDoneClose }) } else { - await actor.rollCarac(caracCode, { diff }) + await actor.rollCarac(caracCode, { diff , onRollDone: RollDialog.onRollDoneClose}) } } } From 75a50257acfaa327374391e450234cdd1da99635 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 13 Dec 2025 02:07:04 +0100 Subject: [PATCH 21/26] =?UTF-8?q?Attaques=20=C3=A0=20distance=20sans=20tok?= =?UTF-8?q?ens?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - correction d'attaques à distance depuis l'onglet combat sans token sélectionné --- changelog.md | 1 + module/combat/distance.mjs | 6 +++--- templates/roll/roll-part-attaque.hbs | 18 ++++++++++-------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/changelog.md b/changelog.md index 10cf4147..f130d0ed 100644 --- a/changelog.md +++ b/changelog.md @@ -14,6 +14,7 @@ - la fenêtre de jet pour les jets depuis un lien texte - affichage des ajustements dans la fenêtre d'attaque avec arme à distance - gestion des défenses contre les armes à distance + - attaque depuis l'onglet combat de la feuille de personnage, sans token sélectionné - défense contre possession - correction du mode "méditation" quand le haut-rêvant ne connait pas de méditation - correction du mode "jeu" quand le personnage ne connait pas de jeux diff --git a/module/combat/distance.mjs b/module/combat/distance.mjs index 0c72cc7c..d0ee26f7 100644 --- a/module/combat/distance.mjs +++ b/module/combat/distance.mjs @@ -36,7 +36,7 @@ export class Distance { } static distance(token, defenderToken) { - if (token && defenderToken) { + if (token instanceof Token && defenderToken instanceof Token) { const ray = new foundry.canvas.geometry.Ray( token.getCenterPoint(), defenderToken.getCenterPoint() @@ -48,7 +48,7 @@ export class Distance { static isVisible(token, defenderToken) { // TODO: regarder les StatusEffect aveuglé? - if (token && defenderToken) { + if (token instanceof Token && defenderToken instanceof Token) { return canvas.effects.visibility.testVisibility(defenderToken.getCenterPoint(), { object: token }) } return true @@ -79,7 +79,7 @@ export class Distance { } static ajustementMouvement(defenderToken) { - if (defenderToken) { + if (defenderToken instanceof Token) { if (defenderToken.actor?.getSurprise(true) != '') return { msg: "immobile (surprise)", diff: 0 }; if (defenderToken.inCombat) return { msg: "en mouvement (combat)", diff: -4 }; } diff --git a/templates/roll/roll-part-attaque.hbs b/templates/roll/roll-part-attaque.hbs index eb5648dd..b47f3bd6 100644 --- a/templates/roll/roll-part-attaque.hbs +++ b/templates/roll/roll-part-attaque.hbs @@ -64,21 +64,23 @@
{{/if}} {{#if current.distance}} +
Attaque à distance {{current.main}} difficulté proposée de {{current.distance.total}} à valider par le Gardien +
    -
  • La cible est à une distance indicative de {{numberFormat current.distance.distance decimals=1}} mètres.
  • -
  • Avec les murs et la lumière, la cible - {{#if current.distance.isVisible}}est{{else}}n'est pas{{/if}} visible. -
  • -
  • Portée {{current.distance.portee.msg}} : {{current.distance.portee.diff}}
  • -
  • De taille {{current.distance.taille.msg}}: {{current.distance.taille.diff}}
  • -
  • Mouvement {{current.distance.activite.msg}}: {{current.distance.activite.diff}}
  • -
+
  • Avec les murs et la lumière, la cible + {{#if current.distance.isVisible}}est{{else}}n'est pas{{/if}} visible. +
  • +
  • La cible est à une distance {{#if (lt current.distance.distance 0)}}indéterminée{{else}}indicative de {{numberFormat current.distance.distance decimals=1}} mètres{{/if}}.
  • +
  • Portée {{current.distance.portee.msg}} : {{current.distance.portee.diff}}
  • +
  • Taille {{current.distance.taille.msg}}: {{current.distance.taille.diff}}
  • +
  • Mouvement {{current.distance.activite.msg}}: {{current.distance.activite.diff}}
  • +
    {{/if}} \ No newline at end of file From a5165a2909ffa3d80f54f451278a045a79631995 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 13 Dec 2025 02:08:34 +0100 Subject: [PATCH 22/26] =?UTF-8?q?Pas=20de=20tactiques=20pour=20les=20attaq?= =?UTF-8?q?ues=20=C3=A0=20distance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- changelog.md | 1 + templates/roll/roll-part-attaque.hbs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/changelog.md b/changelog.md index f130d0ed..f9174f49 100644 --- a/changelog.md +++ b/changelog.md @@ -14,6 +14,7 @@ - la fenêtre de jet pour les jets depuis un lien texte - affichage des ajustements dans la fenêtre d'attaque avec arme à distance - gestion des défenses contre les armes à distance + - pas de tactiques pour les attaques à distance - attaque depuis l'onglet combat de la feuille de personnage, sans token sélectionné - défense contre possession - correction du mode "méditation" quand le haut-rêvant ne connait pas de méditation diff --git a/templates/roll/roll-part-attaque.hbs b/templates/roll/roll-part-attaque.hbs index b47f3bd6..c5dc9af7 100644 --- a/templates/roll/roll-part-attaque.hbs +++ b/templates/roll/roll-part-attaque.hbs @@ -9,12 +9,14 @@ {{/if}} + {{#unless current.distance}} + {{/unless}} {{#if (and refs.isEmpoignadeEnCours (eq current.arme.system.competence 'Dague'))}} From bb51d1c1d0c5133e2c42406f1c204d8997326159 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 13 Dec 2025 02:31:42 +0100 Subject: [PATCH 23/26] Correction erreur sur appel chance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cas particulier non reproduit, le savedRoll ne peut pas être dupliqué. --- module/roll/chat-roll-result.mjs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/module/roll/chat-roll-result.mjs b/module/roll/chat-roll-result.mjs index 02e02540..5fc2eece 100644 --- a/module/roll/chat-roll-result.mjs +++ b/module/roll/chat-roll-result.mjs @@ -197,13 +197,12 @@ export default class ChatRollResult { ) } - async onAppelChanceSuccess(savedRoll, chatMessage) { - const reRoll = foundry.utils.duplicate(savedRoll) + async onAppelChanceSuccess(reRoll, chatMessage) { reRoll.type.retry = true await this.updateChatMessage(chatMessage, reRoll) - const callbacks = [ChatUtility.remover(chatMessage)] - // TODO: annuler les effets + const callbacks = [ChatUtility.remover(chatMessage)] + // TODO: annuler les effets... switch (reRoll.type.current) { case ROLL_TYPE_DEFENSE: this.getCombat(reRoll)?.doRollDefense(reRoll, callbacks) @@ -217,9 +216,9 @@ export default class ChatRollResult { } } - async onAppelChanceEchec(savedRoll, chatMessage) { - savedRoll.type.retry = true - await this.updateChatMessage(chatMessage, savedRoll) + async onAppelChanceEchec(reRoll, chatMessage) { + reRoll.type.retry = true + await this.updateChatMessage(chatMessage, reRoll) } onClickAppelDestinee(event) { From c61cc5da189fed87419ba224bb37560a7473a3dc Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 13 Dec 2025 02:43:58 +0100 Subject: [PATCH 24/26] =?UTF-8?q?Am=C3=A9lioration=20des=20remoteActorCall?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/actor/base-actor.js | 20 ++++++++++++-------- module/misc.js | 13 +++++-------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/module/actor/base-actor.js b/module/actor/base-actor.js index 17a3cb6d..a28b28f2 100644 --- a/module/actor/base-actor.js +++ b/module/actor/base-actor.js @@ -68,19 +68,23 @@ export class RdDBaseActor extends Actor { return false } else { - game.socket.emit(SYSTEM_SOCKET_ID, { - msg: "msg_remote_actor_call", - data: callData, - userId: Misc.firstConnectedGMId() - }) - return true + const gmUserId = Misc.firstConnectedGMId() + if (gmUserId){ + game.socket.emit(SYSTEM_SOCKET_ID, { + msg: "msg_remote_actor_call", + data: callData, + userId: gmUserId + }) + return true + } + return false } } static onRemoteActorCall(callData, userId) { - const actor = RdDBaseActor.getRealActor(callData?.actorId, callData?.tokenId); if (userId == game.user.id) { // Seul le joueur choisi effectue l'appel: le joueur courant si propriétaire de l'actor, ou le MJ sinon + const actor = RdDBaseActor.getRealActor(callData?.actorId, callData?.tokenId); const args = callData.args; console.info(`RdDBaseActor.onRemoteActorCall: pour l'Actor ${callData.actorId}, appel de RdDBaseActor.${callData.method}(`, ...args, ')'); actor[callData.method](...args); @@ -461,7 +465,7 @@ export class RdDBaseActor extends Actor { ui.notifications.info("Inutile de se vendre à soi-même"); return; } - if (!Misc.isFirstConnectedGM()) { + if (!game.user.isGM) { RdDBaseActor.remoteActorCall({ actorId: achat.vendeurId ?? achat.acheteurId, method: 'achatVente', args: [achat] diff --git a/module/misc.js b/module/misc.js index 38417bb6..cf3c69f9 100644 --- a/module/misc.js +++ b/module/misc.js @@ -200,10 +200,7 @@ export class Misc { } static firstConnectedGM() { - if (foundry.utils.isNewerVersion(game.release.version, '12.0')) { - return game.users.activeGM - } - return game.users.find(u => u.isGM && u.active); + return game.users.activeGM } static connectedGMs() { @@ -223,7 +220,7 @@ export class Misc { * and there is no connected GM */ static documentIfResponsible(document) { - if (Misc.isFirstConnectedGM() || (Misc.connectedGMs().length == 0 && Misc.isFirstOwnerPlayer(document))) { + if (game.users.activeGM || (Misc.connectedGMs().length == 0 && Misc.isFirstOwnerPlayer(document))) { return document } return undefined @@ -252,15 +249,15 @@ export class Misc { * @returns true pour un seul utilisateur: le premier GM connecté par ordre d'id */ static isFirstConnectedGM() { - return game.user == Misc.firstConnectedGM(); + return game.user == game.users.activeGM } static hasConnectedGM() { - return Misc.firstConnectedGM(); + return game.users.activeGM } static firstConnectedGMId() { - return Misc.firstConnectedGM()?.id; + return game.users.activeGM?.id; } /* -------------------------------------------- */ From f6581c7b3b5105c0684ea62d7652a1cda478789d Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 13 Dec 2025 02:45:07 +0100 Subject: [PATCH 25/26] =?UTF-8?q?Changement=20de=20message=20de=20non=20ap?= =?UTF-8?q?pr=C3=A9ciation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quand l'appréciation ne donne pas de jet de moral, le message donnant les raisons est ajouté dans le tchat --- module/moral/apprecier.mjs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/module/moral/apprecier.mjs b/module/moral/apprecier.mjs index 38d77895..63cdafe6 100644 --- a/module/moral/apprecier.mjs +++ b/module/moral/apprecier.mjs @@ -1,3 +1,4 @@ +import { ChatUtility } from "../chat-utility.js" import { ITEM_TYPES } from "../constants.js" import { SANS_COMPETENCE } from "../item/base-items.js" import { Misc } from "../misc.js" @@ -166,7 +167,10 @@ export class Apprecier { async rollMoral(moral = undefined) { if (this.raisons.length > 0) { - ui.notifications.info('Pas de jet de moral:' + Misc.concat(this.raisons.map(r => `
    - ${r}`))) + ChatMessage.create({ + whisper: ChatUtility.getOwners(this.actor), + content: 'Pas de jet de moral:' + Misc.concat(this.raisons.map(r => `
    - ${r}`)) + }) return } From c4794cd276b9219c6e9b5a5742eb373f85ab77d0 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 13 Dec 2025 02:54:24 +0100 Subject: [PATCH 26/26] =?UTF-8?q?La=20fen=C3=AAtre=20d'appr=C3=A9ciation?= =?UTF-8?q?=20doit=20se=20fermer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit la fenêtre d'appréciation se ferme automatiquement --- module/moral/apprecier.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/module/moral/apprecier.mjs b/module/moral/apprecier.mjs index 63cdafe6..384b4baf 100644 --- a/module/moral/apprecier.mjs +++ b/module/moral/apprecier.mjs @@ -150,7 +150,8 @@ export class Apprecier { callbacks: [ async r => await this.onRollAppreciation(r), ...rollCallbacks - ] + ], + onRollDone: RollDialog.onRollDoneClose }) }