From 053bc23d120f2f567b40670aab158becbcd995bd Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Mon, 29 Sep 2025 01:47:35 +0200 Subject: [PATCH 01/12] Move HUD button attaque --- css/foundryvtt-reve-de-dragon.css | 6 +++--- less/foundryvtt-reve-de-dragon.less | 6 +++--- module/rdd-token-hud.js | 14 ++++++++------ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/css/foundryvtt-reve-de-dragon.css b/css/foundryvtt-reve-de-dragon.css index 36ac4ced..c2740c49 100644 --- a/css/foundryvtt-reve-de-dragon.css +++ b/css/foundryvtt-reve-de-dragon.css @@ -1954,13 +1954,13 @@ select, justify-content: flex-start; flex-direction: column; position: absolute; - top: 4.6rem; - left: -19rem; + top: 10rem; + left: -9rem; } .system-foundryvtt-reve-de-dragon .token-hud-ext.soins { flex-direction: column; position: absolute; - top: 14.7rem; + top: 15.5rem; left: -6rem; max-width: 8rem; line-height: 1rem; diff --git a/less/foundryvtt-reve-de-dragon.less b/less/foundryvtt-reve-de-dragon.less index f204ceab..4d129e2a 100644 --- a/less/foundryvtt-reve-de-dragon.less +++ b/less/foundryvtt-reve-de-dragon.less @@ -1319,13 +1319,13 @@ justify-content: flex-start; flex-direction: column; position: absolute; - top: 4.6rem; - left: -19rem; + top: 10rem; + left: -9rem; } .token-hud-ext.soins { flex-direction: column; position: absolute; - top: 14.7rem; + top: 15.5rem; left: -6rem; max-width: 8rem; line-height: 1rem; diff --git a/module/rdd-token-hud.js b/module/rdd-token-hud.js index 83553c8f..ac6bacaf 100644 --- a/module/rdd-token-hud.js +++ b/module/rdd-token-hud.js @@ -50,7 +50,7 @@ export class RdDTokenHud { { name: 'Initiative -1', command: 'dec', value: -0.01 }] }; const controlIconCombat = $(html).find('.control-icon[data-action=combat]'); - await RdDTokenHud._configureSubMenu(controlIconCombat, + await RdDTokenHud._configureSubMenu(it => controlIconCombat.after(it), 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.hbs', hudData, (event) => { @@ -69,8 +69,10 @@ export class RdDTokenHud { static async addExtensionHudCombat(html, combatant, token, actions) { const hudData = { combatant, token, actions, commandes: [] }; - const controlIconTarget = $(html).find('.control-icon[data-action=target]'); - await RdDTokenHud._configureSubMenu(controlIconTarget, 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.hbs', hudData, + const divColLeft = $(html).find('div.col.left'); + await RdDTokenHud._configureSubMenu(it => divColLeft.append(it), + 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.hbs', + hudData, (event) => { const actionIndex = event.currentTarget.attributes['data-action-index']?.value; const action = hudData.actions[actionIndex]; @@ -90,7 +92,7 @@ export class RdDTokenHud { const hudSoins = { blessures: target.actor.blessuresASoigner() ?? [] }; if (hudSoins.blessures.length > 0) { const controlIconTarget = $(html).find('.control-icon[data-action=combat]'); - await RdDTokenHud._configureSubMenu(controlIconTarget, + await RdDTokenHud._configureSubMenu(it => controlIconTarget.after(it), 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-soins.hbs', hudSoins, (event) => { @@ -129,7 +131,7 @@ export class RdDTokenHud { } /* -------------------------------------------- */ - static async _configureSubMenu(insertionPoint, template, hudData, onMenuItem) { + static async _configureSubMenu(insertMethod, template, hudData, onMenuItem) { const hud = $(await foundry.applications.handlebars.renderTemplate(template, hudData)); const list = hud.find('div.rdd-hud-list'); @@ -138,7 +140,7 @@ export class RdDTokenHud { hud.find('img.rdd-hud-togglebutton').click(event => RdDTokenHud._toggleHudListActive(hud, list)); list.find('.rdd-hud-menu').click(onMenuItem); - insertionPoint.after(hud); + insertMethod(hud); } static _toggleHudListActive(hud, list) { From d0ba1ebf99e5d41220fa934d62745947772cddcc Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Tue, 30 Sep 2025 02:03:02 +0200 Subject: [PATCH 02/12] utilisation de renderTemplate "interne" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Import de foundry.applications.handlebars.renderTemplate au travers d'une constante pour éliminer les warnings --- module/achat-vente/chat-vente.js | 2 +- module/achat-vente/dialog-item-achat.js | 1 + module/achat-vente/dialog-item-vente.js | 1 + module/actor.js | 2 +- module/actor/base-actor-reve.js | 2 +- module/actor/base-actor.js | 4 ++-- module/apps/textroll/text-roll-formatter.js | 1 + module/chat-utility.js | 4 ++-- module/coeur/rdd-coeur.js | 1 + module/constants.js | 2 ++ module/dialog-choix-xp-carac.js | 1 + module/dialog-chronologie.js | 2 +- module/dialog-create-signedraconique.js | 1 + module/dialog-fabriquer-potion.js | 1 + module/dialog-item-consommer.js | 1 + module/dialog-select.js | 1 + module/dialog-split-item.js | 2 +- module/dialog-validation-encaissement.js | 2 +- module/enchantement/dialog-enchanter.js | 2 +- module/item.js | 2 +- module/rdd-combat.js | 2 +- module/rdd-commands.js | 1 + module/rdd-empoignade.js | 2 +- module/rdd-meteo.js | 1 + module/rdd-namegen.js | 1 + module/rdd-resolution-table.js | 3 ++- module/rdd-roll-encaisser.js | 2 +- module/rdd-roll-resolution-table.js | 1 + module/rdd-roll-result.js | 3 ++- module/rdd-roll.js | 7 +++---- module/rdd-tmr-dialog.js | 6 +++--- module/rdd-token-hud.js | 3 ++- module/roll/chat-roll-result.mjs | 3 ++- module/roll/roll-dialog.mjs | 3 ++- module/settings/system-compendiums.js | 2 +- module/sommeil/dialog-chateau-dormant.js | 3 ++- module/sommeil/dialog-repos.js | 1 + module/sommeil/dialog-stress.js | 1 + module/time/rdd-calendrier.js | 2 +- module/tirage/fenetre-recherche-tirage.js | 1 + module/tmr-rencontres.js | 3 ++- module/tmr/effets-rencontres.js | 1 + module/voyage/dialog-fatigue-voyage.js | 2 +- 43 files changed, 57 insertions(+), 32 deletions(-) diff --git a/module/achat-vente/chat-vente.js b/module/achat-vente/chat-vente.js index a921a356..66a0f2a9 100644 --- a/module/achat-vente/chat-vente.js +++ b/module/achat-vente/chat-vente.js @@ -1,4 +1,4 @@ -import { SYSTEM_RDD } from "../constants.js"; +import { renderTemplate, SYSTEM_RDD } from "../constants.js"; import { RdDUtility } from "../rdd-utility.js"; const DETAIL_VENTE = 'detailVente'; diff --git a/module/achat-vente/dialog-item-achat.js b/module/achat-vente/dialog-item-achat.js index 58992d7e..09b686ff 100644 --- a/module/achat-vente/dialog-item-achat.js +++ b/module/achat-vente/dialog-item-achat.js @@ -1,3 +1,4 @@ +import { renderTemplate } from "../constants.js"; import { Misc } from "../misc.js"; import { RdDUtility } from "../rdd-utility.js"; import { ChatVente } from "./chat-vente.js"; diff --git a/module/achat-vente/dialog-item-vente.js b/module/achat-vente/dialog-item-vente.js index 64a2166e..13c3f448 100644 --- a/module/achat-vente/dialog-item-vente.js +++ b/module/achat-vente/dialog-item-vente.js @@ -1,3 +1,4 @@ +import { renderTemplate } from "../constants.js"; import { HtmlUtility } from "../html-utility.js"; import { RdDUtility } from "../rdd-utility.js"; import { ChatVente } from "./chat-vente.js"; diff --git a/module/actor.js b/module/actor.js index e683cdf5..ec22cebe 100644 --- a/module/actor.js +++ b/module/actor.js @@ -19,7 +19,7 @@ import { DialogConsommer } from "./dialog-item-consommer.js"; import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js"; import { RollDataAjustements } from "./rolldata-ajustements.js"; import { RdDPossession } from "./rdd-possession.js"; -import { ACTOR_TYPES, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; +import { ACTOR_TYPES, renderTemplate, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; import { RdDConfirm } from "./rdd-confirm.js"; import { DialogRepos } from "./sommeil/dialog-repos.js"; import { RdDBaseActor } from "./actor/base-actor.js"; diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index 9207ade4..6e5ab325 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -1,4 +1,4 @@ -import { ENTITE_INCARNE, SHOW_DICE, SYSTEM_RDD } from "../constants.js"; +import { ENTITE_INCARNE, renderTemplate, SHOW_DICE, SYSTEM_RDD } from "../constants.js"; import { Grammar } from "../grammar.js"; import { Misc } from "../misc.js"; import { RdDResolutionTable } from "../rdd-resolution-table.js"; diff --git a/module/actor/base-actor.js b/module/actor/base-actor.js index b12edb50..2d3ca6f9 100644 --- a/module/actor/base-actor.js +++ b/module/actor/base-actor.js @@ -1,6 +1,6 @@ import { ChatVente } from "../achat-vente/chat-vente.js"; import { ChatUtility } from "../chat-utility.js"; -import { SYSTEM_SOCKET_ID } from "../constants.js"; +import { renderTemplate, SYSTEM_SOCKET_ID } from "../constants.js"; import { Grammar } from "../grammar.js"; import { Monnaie } from "../item-monnaie.js"; import { ITEM_TYPES } from "../constants.js"; @@ -738,7 +738,7 @@ export class RdDBaseActor extends Actor { name: this.getAlias(), system: { description: this.system.description } } - foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/post-actor.hbs', chatData) + renderTemplate('systems/foundryvtt-reve-de-dragon/templates/post-actor.hbs', chatData) .then(html => ChatMessage.create(RdDUtility.chatDataSetup(html, modeOverride))); } diff --git a/module/apps/textroll/text-roll-formatter.js b/module/apps/textroll/text-roll-formatter.js index 7e0dbc05..73015c97 100644 --- a/module/apps/textroll/text-roll-formatter.js +++ b/module/apps/textroll/text-roll-formatter.js @@ -1,3 +1,4 @@ +import { renderTemplate } from "../../constants.js"; export class TextRollManager { diff --git a/module/chat-utility.js b/module/chat-utility.js index c1649e3c..a1c9e1d9 100644 --- a/module/chat-utility.js +++ b/module/chat-utility.js @@ -1,5 +1,5 @@ import { Misc } from "./misc.js"; -import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; +import { renderTemplate, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js"; @@ -190,7 +190,7 @@ export class ChatUtility { if (rddTimestamp) { const timestamp = new RdDTimestamp(rddTimestamp); const timestampData = timestamp.toCalendrier(); - const dateHeure = await foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/common/date-heure.hbs', timestampData); + const dateHeure = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/common/date-heure.hbs', timestampData); $(html).find('header.message-header .message-sender').after(dateHeure) } } diff --git a/module/coeur/rdd-coeur.js b/module/coeur/rdd-coeur.js index d96b2e7f..4954f725 100644 --- a/module/coeur/rdd-coeur.js +++ b/module/coeur/rdd-coeur.js @@ -1,5 +1,6 @@ import { RdDBaseActor } from "../actor/base-actor.js"; import { ChatUtility } from "../chat-utility.js"; +import { renderTemplate } from "../constants.js"; const INFO_COEUR = 'info-coeur'; diff --git a/module/constants.js b/module/constants.js index 6b013361..201cd882 100644 --- a/module/constants.js +++ b/module/constants.js @@ -9,6 +9,8 @@ export const ENTITE_INCARNE = 'incarne' export const ENTITE_NONINCARNE = 'nonincarne' export const ENTITE_BLURETTE = 'blurette' +export const renderTemplate = foundry.applications.handlebars.renderTemplate + export const RDD_CONFIG = { niveauEthylisme : [ {value: "1", label: "Aucun"}, diff --git a/module/dialog-choix-xp-carac.js b/module/dialog-choix-xp-carac.js index 9afdda88..9ed6d428 100644 --- a/module/dialog-choix-xp-carac.js +++ b/module/dialog-choix-xp-carac.js @@ -1,3 +1,4 @@ +import { renderTemplate } from "./constants.js" export class DialogChoixXpCarac extends Dialog { diff --git a/module/dialog-chronologie.js b/module/dialog-chronologie.js index f67e7793..e53eb6c1 100644 --- a/module/dialog-chronologie.js +++ b/module/dialog-chronologie.js @@ -1,4 +1,4 @@ -import { SYSTEM_RDD } from "./constants.js"; +import { renderTemplate, SYSTEM_RDD } from "./constants.js"; import { Grammar } from "./grammar.js"; import { HtmlUtility } from "./html-utility.js"; import { RdDTimestamp } from "./time/rdd-timestamp.js"; diff --git a/module/dialog-create-signedraconique.js b/module/dialog-create-signedraconique.js index 60b67b01..92a5e873 100644 --- a/module/dialog-create-signedraconique.js +++ b/module/dialog-create-signedraconique.js @@ -1,4 +1,5 @@ import { ChatUtility } from "./chat-utility.js"; +import { renderTemplate } from "./constants.js"; import { HtmlUtility } from "./html-utility.js"; import { RdDItemSigneDraconique } from "./item/signedraconique.js"; import { TMRUtility } from "./tmr-utility.js"; diff --git a/module/dialog-fabriquer-potion.js b/module/dialog-fabriquer-potion.js index 24a157d9..6e88092d 100644 --- a/module/dialog-fabriquer-potion.js +++ b/module/dialog-fabriquer-potion.js @@ -1,3 +1,4 @@ +import { renderTemplate } from "./constants.js"; import { Misc } from "./misc.js"; import { RdDUtility } from "./rdd-utility.js"; diff --git a/module/dialog-item-consommer.js b/module/dialog-item-consommer.js index a71ffaeb..ac15e261 100644 --- a/module/dialog-item-consommer.js +++ b/module/dialog-item-consommer.js @@ -1,3 +1,4 @@ +import { renderTemplate } from "./constants.js"; import { Misc } from "./misc.js"; export class DialogConsommer extends Dialog { diff --git a/module/dialog-select.js b/module/dialog-select.js index 4107d5c0..33253e2a 100644 --- a/module/dialog-select.js +++ b/module/dialog-select.js @@ -1,3 +1,4 @@ +import { renderTemplate } from "./constants.js" export class DialogSelect extends Dialog { static extractIdNameImg(it) { return { id: it.id, name: it.name, img: it.img } } diff --git a/module/dialog-split-item.js b/module/dialog-split-item.js index 79c5404c..2f4419aa 100644 --- a/module/dialog-split-item.js +++ b/module/dialog-split-item.js @@ -1,4 +1,4 @@ -import { Misc } from "./misc.js"; +import { renderTemplate } from "./constants.js"; export class DialogSplitItem extends Dialog { diff --git a/module/dialog-validation-encaissement.js b/module/dialog-validation-encaissement.js index 825b4c06..90bbf91d 100644 --- a/module/dialog-validation-encaissement.js +++ b/module/dialog-validation-encaissement.js @@ -1,4 +1,4 @@ -import { HIDE_DICE, SHOW_DICE } from "./constants.js"; +import { HIDE_DICE, renderTemplate, SHOW_DICE } from "./constants.js"; import { RdDUtility } from "./rdd-utility.js"; /** diff --git a/module/enchantement/dialog-enchanter.js b/module/enchantement/dialog-enchanter.js index 15e1c431..a64533bf 100644 --- a/module/enchantement/dialog-enchanter.js +++ b/module/enchantement/dialog-enchanter.js @@ -1,4 +1,4 @@ -import { ITEM_TYPES } from "../constants.js" +import { ITEM_TYPES, renderTemplate } from "../constants.js" import { RdDItemSort } from "../item-sort.js" import { Misc } from "../misc.js" diff --git a/module/item.js b/module/item.js index 5df8e478..44829cd2 100644 --- a/module/item.js +++ b/module/item.js @@ -1,4 +1,4 @@ -import { ITEM_TYPES } from "./constants.js"; +import { ITEM_TYPES, renderTemplate } from "./constants.js"; import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, CATEGORIES_COMPETENCES, CATEGORIES_COMPETENCES_CREATURES } from "./item/base-items.js"; import { ITEM_ACTIONS, DEFAULT_ACTIONS, COMMON_ACTIONS } from "./item/item-actions.js"; diff --git a/module/rdd-combat.js b/module/rdd-combat.js index 76a27948..ef5a4bc1 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -1,5 +1,5 @@ import { ChatUtility } from "./chat-utility.js"; -import { ENTITE_BLURETTE, HIDE_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; +import { ENTITE_BLURETTE, HIDE_DICE, renderTemplate, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; import { Grammar } from "./grammar.js"; import { Misc } from "./misc.js"; import { RdDBonus } from "./rdd-bonus.js"; diff --git a/module/rdd-commands.js b/module/rdd-commands.js index 158bc946..762f8d23 100644 --- a/module/rdd-commands.js +++ b/module/rdd-commands.js @@ -19,6 +19,7 @@ import { TMRUtility } from "./tmr-utility.js"; import { DialogFatigueVoyage } from "./voyage/dialog-fatigue-voyage.js"; import { ChatUtility } from "./chat-utility.js"; import { RdDRollResult } from "./rdd-roll-result.js"; +import { renderTemplate } from "./constants.js"; const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/; diff --git a/module/rdd-empoignade.js b/module/rdd-empoignade.js index f7fce4a0..475c6147 100644 --- a/module/rdd-empoignade.js +++ b/module/rdd-empoignade.js @@ -1,5 +1,5 @@ import { STATUSES } from "./settings/status-effects.js"; -import { ITEM_TYPES } from "./constants.js"; +import { ITEM_TYPES, renderTemplate } from "./constants.js"; import { ChatUtility } from "./chat-utility.js"; import { RdDRollResult } from "./rdd-roll-result.js"; import { RdDRoll } from "./rdd-roll.js"; diff --git a/module/rdd-meteo.js b/module/rdd-meteo.js index e3512f22..d1cfb738 100644 --- a/module/rdd-meteo.js +++ b/module/rdd-meteo.js @@ -1,4 +1,5 @@ import { ChatUtility } from "./chat-utility.js" +import { renderTemplate } from "./constants.js" const vents = [ { min: 0, max: 0, valeur: 'Calme' }, diff --git a/module/rdd-namegen.js b/module/rdd-namegen.js index f0768cf7..9429e6fe 100644 --- a/module/rdd-namegen.js +++ b/module/rdd-namegen.js @@ -1,5 +1,6 @@ import { RdDBaseActor } from "./actor/base-actor.js"; import { ChatUtility } from "./chat-utility.js"; +import { renderTemplate } from "./constants.js"; import { Misc } from "./misc.js"; import { RdDDice } from "./rdd-dice.js"; diff --git a/module/rdd-resolution-table.js b/module/rdd-resolution-table.js index 99d51688..896b41b0 100644 --- a/module/rdd-resolution-table.js +++ b/module/rdd-resolution-table.js @@ -1,3 +1,4 @@ +import { renderTemplate } from "./constants.js"; import { Misc } from "./misc.js"; import { RdDDice } from "./rdd-dice.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; @@ -236,7 +237,7 @@ export class RdDResolutionTable { maxCarac = Math.min(maxCarac, minCarac + 20); minLevel = Math.max(minLevel, -10); maxLevel = Math.max(Math.min(maxLevel, 30), minLevel + colonnes); - return await foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/resolution-table.hbs', { + return await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/resolution-table.hbs', { carac: carac, difficulte: level, min: minLevel, diff --git a/module/rdd-roll-encaisser.js b/module/rdd-roll-encaisser.js index e11b3a23..058c93ff 100644 --- a/module/rdd-roll-encaisser.js +++ b/module/rdd-roll-encaisser.js @@ -1,4 +1,4 @@ -import { ENTITE_BLURETTE, ENTITE_INCARNE } from "./constants.js"; +import { ENTITE_BLURETTE, ENTITE_INCARNE, renderTemplate } from "./constants.js"; import { RdDUtility } from "./rdd-utility.js"; /** diff --git a/module/rdd-roll-resolution-table.js b/module/rdd-roll-resolution-table.js index 6901c523..df19358b 100644 --- a/module/rdd-roll-resolution-table.js +++ b/module/rdd-roll-resolution-table.js @@ -1,3 +1,4 @@ +import { renderTemplate } from "./constants.js"; import { Misc } from "./misc.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js"; diff --git a/module/rdd-roll-result.js b/module/rdd-roll-result.js index 3087ff2f..2495e366 100644 --- a/module/rdd-roll-result.js +++ b/module/rdd-roll-result.js @@ -1,4 +1,5 @@ import { ChatUtility } from "./chat-utility.js"; +import { renderTemplate } from "./constants.js"; export class RdDRollResult { @@ -13,6 +14,6 @@ export class RdDRollResult { static async buildRollDataHtml(rollData, template = 'chat-resultat-general.hbs') { rollData.show = rollData.show || {}; - return await foundry.applications.handlebars.renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/${template}`, rollData); + return await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/${template}`, rollData); } } diff --git a/module/rdd-roll.js b/module/rdd-roll.js index 7ae8900d..12fc6af9 100644 --- a/module/rdd-roll.js +++ b/module/rdd-roll.js @@ -8,8 +8,7 @@ import { RdDCarac } from "./rdd-carac.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { Grammar } from "./grammar.js"; -import { ACTOR_TYPES } from "./constants.js"; -import { RdDUtility } from "./rdd-utility.js"; +import { ACTOR_TYPES, renderTemplate } from "./constants.js"; /** * Extend the base Dialog entity to select roll parameters @@ -23,7 +22,7 @@ export class RdDRoll extends Dialog { RdDRoll._ensureCorrectAction(action); RdDRoll._setDefaultOptions(actor, rollData); - const html = await foundry.applications.handlebars.renderTemplate(dialogConfig.html, rollData); + const html = await renderTemplate(dialogConfig.html, rollData); let options = { classes: ["rdd-roll-dialog"], width: 650, height: 'fit-content', 'z-index': 99999, close: html => { } }; if (dialogConfig.close) { @@ -345,7 +344,7 @@ export class RdDRoll extends Dialog { /* -------------------------------------------- */ async buildAjustements(rollData) { - return await foundry.applications.handlebars.renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.hbs`, rollData); + return await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.hbs`, rollData); } /* -------------------------------------------- */ diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js index dbf635f5..d6c77a4a 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -1,4 +1,4 @@ -import { SHOW_DICE, SYSTEM_RDD } from "./constants.js"; +import { renderTemplate, SHOW_DICE, SYSTEM_RDD } from "./constants.js"; import { RollDataAjustements } from "./rolldata-ajustements.js"; import { RdDUtility } from "./rdd-utility.js"; import { COORD_TMR_INCONNU, TMRUtility } from "./tmr-utility.js"; @@ -47,7 +47,7 @@ export class RdDTMRDialog extends Dialog { static async create(actor, tmrData) { await PixiTMR.init() - let html = await foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.hbs', tmrData); + let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.hbs', tmrData); if (tmrData.mode != 'visu' && !game.user.isGM) { ChatMessage.create({ content: actor.name + " est monté dans les TMR en mode : " + tmrData.mode, whisper: ChatUtility.getGMs() }); } @@ -508,7 +508,7 @@ export class RdDTMRDialog extends Dialog { ChatMessage.create({ whisper: ChatUtility.getOwners(this.actor), - content: await foundry.applications.handlebars.renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-rencontre-tmr.hbs`, rencData) + content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-rencontre-tmr.hbs`, rencData) }); this.$updateValuesDisplay(); diff --git a/module/rdd-token-hud.js b/module/rdd-token-hud.js index ac6bacaf..9fa182b3 100644 --- a/module/rdd-token-hud.js +++ b/module/rdd-token-hud.js @@ -1,4 +1,5 @@ /* -------------------------------------------- */ +import { renderTemplate } from "./constants.js"; import { HtmlUtility } from "./html-utility.js"; import { RdDCombatManager } from "./rdd-combat.js"; import { Targets } from "./targets.js"; @@ -132,7 +133,7 @@ export class RdDTokenHud { /* -------------------------------------------- */ static async _configureSubMenu(insertMethod, template, hudData, onMenuItem) { - const hud = $(await foundry.applications.handlebars.renderTemplate(template, hudData)); + const hud = $(await renderTemplate(template, hudData)); const list = hud.find('div.rdd-hud-list'); RdDTokenHud._toggleHudListActive(hud, list); diff --git a/module/roll/chat-roll-result.mjs b/module/roll/chat-roll-result.mjs index 7c22ad21..e30f1e72 100644 --- a/module/roll/chat-roll-result.mjs +++ b/module/roll/chat-roll-result.mjs @@ -4,6 +4,7 @@ import { RdDCarac } from "../rdd-carac.js" import { RdDCombat } from "../rdd-combat.js" import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs" import { RdDResolutionTable } from "../rdd-resolution-table.js" +import { RDD_CONFIG, renderTemplate } from "../constants.js" export default class ChatRollResult { static init() { @@ -76,7 +77,7 @@ export default class ChatRollResult { async buildRollHtml(roll) { const template = `systems/foundryvtt-reve-de-dragon/templates/roll/result/chat-${roll.type.current}.hbs` - return await foundry.applications.handlebars.renderTemplate(template, roll) + return await renderTemplate(template, roll) } async chatListeners(html) { diff --git a/module/roll/roll-dialog.mjs b/module/roll/roll-dialog.mjs index 2ecc326e..6a243ad9 100644 --- a/module/roll/roll-dialog.mjs +++ b/module/roll/roll-dialog.mjs @@ -39,6 +39,7 @@ import { RollDialogAdapter } from "./roll-dialog-adapter.mjs"; import { ROLLDIALOG_SECTION } from "./roll-part.mjs"; import { ROLL_TYPE_COMP } from "./roll-constants.mjs"; import ChatRollResult from "./chat-roll-result.mjs"; +import { renderTemplate } from "../constants.js"; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api @@ -368,7 +369,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 } async buildHTMLTable(carac, diff) { - return await foundry.applications.handlebars.renderTemplate('roll-table', { carac, diff }) + return await renderTemplate('roll-table', { carac, diff }) } async _prepareContext() { diff --git a/module/settings/system-compendiums.js b/module/settings/system-compendiums.js index fe782aaf..f602b80a 100644 --- a/module/settings/system-compendiums.js +++ b/module/settings/system-compendiums.js @@ -1,5 +1,5 @@ import { ChatUtility } from "../chat-utility.js"; -import { HIDE_DICE, SYSTEM_RDD } from "../constants.js"; +import { HIDE_DICE, renderTemplate, SYSTEM_RDD } from "../constants.js"; import { Grammar } from "../grammar.js"; import { RdDItem } from "../item.js"; import { Misc } from "../misc.js"; diff --git a/module/sommeil/dialog-chateau-dormant.js b/module/sommeil/dialog-chateau-dormant.js index c01075dc..64218b62 100644 --- a/module/sommeil/dialog-chateau-dormant.js +++ b/module/sommeil/dialog-chateau-dormant.js @@ -1,3 +1,4 @@ +import { renderTemplate } from "../constants.js"; export class DialogChateauDormant extends Dialog { @@ -9,7 +10,7 @@ export class DialogChateauDormant extends Dialog { motifStress: `Nuit du ${date}`, finChateauDormant: game.system.rdd.calendrier.getTimestampFinChateauDormant() }; - const html = await foundry.applications.handlebars.renderTemplate("systems/foundryvtt-reve-de-dragon/templates/sommeil/dialog-chateau-dormant.hbs", + const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/sommeil/dialog-chateau-dormant.hbs", dialogData); new DialogChateauDormant(dialogData, html) diff --git a/module/sommeil/dialog-repos.js b/module/sommeil/dialog-repos.js index 7374a520..a7267e51 100644 --- a/module/sommeil/dialog-repos.js +++ b/module/sommeil/dialog-repos.js @@ -1,3 +1,4 @@ +import { renderTemplate } from "../constants.js"; import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"; import { EffetsDraconiques } from "../tmr/effets-draconiques.js"; diff --git a/module/sommeil/dialog-stress.js b/module/sommeil/dialog-stress.js index 0b30c323..cdf7928e 100644 --- a/module/sommeil/dialog-stress.js +++ b/module/sommeil/dialog-stress.js @@ -1,3 +1,4 @@ +import { renderTemplate } from "../constants.js"; export class DialogStress extends Dialog { diff --git a/module/time/rdd-calendrier.js b/module/time/rdd-calendrier.js index 1c1671c5..83eeee3a 100644 --- a/module/time/rdd-calendrier.js +++ b/module/time/rdd-calendrier.js @@ -4,7 +4,7 @@ import { RdDResolutionTable } from "../rdd-resolution-table.js"; import { RdDDice } from "../rdd-dice.js"; import { Misc } from "../misc.js"; import { DialogChronologie } from "../dialog-chronologie.js"; -import { HIDE_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "../constants.js"; +import { HIDE_DICE, renderTemplate, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "../constants.js"; import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"; import { DialogChateauDormant } from "../sommeil/dialog-chateau-dormant.js"; import { APP_ASTROLOGIE_REFRESH, AppAstrologie } from "../sommeil/app-astrologie.js"; diff --git a/module/tirage/fenetre-recherche-tirage.js b/module/tirage/fenetre-recherche-tirage.js index 932778d0..c72ee938 100644 --- a/module/tirage/fenetre-recherche-tirage.js +++ b/module/tirage/fenetre-recherche-tirage.js @@ -4,6 +4,7 @@ import { Misc } from "../misc.js"; import { CompendiumTableHelpers } from '../settings/system-compendiums.js'; import { RdDRaretes } from '../item/raretes.js'; import { Grammar } from '../grammar.js'; +import { renderTemplate } from '../constants.js'; const FILTER_GROUPS = [ { group: 'type', label: "Type d'objet" }, diff --git a/module/tmr-rencontres.js b/module/tmr-rencontres.js index 684fdf85..2281517e 100644 --- a/module/tmr-rencontres.js +++ b/module/tmr-rencontres.js @@ -1,3 +1,4 @@ +import { renderTemplate } from "./constants.js"; import { Grammar } from "./grammar.js"; import { Misc } from "./misc.js"; import { RdDDice } from "./rdd-dice.js"; @@ -102,7 +103,7 @@ export class TMRRencontres { /* -------------------------------------------- */ async $chatRolledRencontre(row, rencontre, tmr) { - const flavorContent = await foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table-roll-rencontre.hbs', + const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table-roll-rencontre.hbs', { roll: row.roll, rencontre, diff --git a/module/tmr/effets-rencontres.js b/module/tmr/effets-rencontres.js index 183c876c..675218a4 100644 --- a/module/tmr/effets-rencontres.js +++ b/module/tmr/effets-rencontres.js @@ -1,5 +1,6 @@ import { ExperienceLog, XP_TOPIC } from "../actor/experience-log.js"; import { ChatUtility } from "../chat-utility.js"; +import { renderTemplate } from "../constants.js"; import { Poetique } from "../poetique.js"; import { RdDDice } from "../rdd-dice.js"; import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"; diff --git a/module/voyage/dialog-fatigue-voyage.js b/module/voyage/dialog-fatigue-voyage.js index 18c96e41..d1adce19 100644 --- a/module/voyage/dialog-fatigue-voyage.js +++ b/module/voyage/dialog-fatigue-voyage.js @@ -1,4 +1,4 @@ -import { ITEM_TYPES } from "../constants.js" +import { ITEM_TYPES, renderTemplate } from "../constants.js" import { RdDItemCompetence } from "../item-competence.js" import { ChatUtility } from "../chat-utility.js" import { Misc } from "../misc.js" From 7370b633db7d7b459a8ed180ee38302bf1bef755 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Tue, 30 Sep 2025 01:33:08 +0200 Subject: [PATCH 03/12] Gestion attaques v2 et initiative --- assets/ui/part-finesse.svg | 1 + assets/ui/part-force.svg | 1 + assets/ui/part-rapidite.svg | 1 + css/foundryvtt-reve-de-dragon.css | 54 ++-- less/foundryvtt-reve-de-dragon.less | 14 +- less/roll-chat.less | 153 ++++++----- module/actor-token.mjs | 3 + module/actor.js | 23 +- module/actor/base-actor-reve.js | 56 ++++ module/actor/base-actor-sang.js | 12 +- module/actor/base-actor-sheet.js | 6 +- module/actor/base-actor.js | 8 +- module/constants.js | 72 +++-- module/initiative.mjs | 64 ++++- module/item-competencecreature.js | 10 +- module/item/arme.js | 13 +- module/item/mapping-creature-arme.mjs | 3 +- module/misc.js | 10 +- module/rdd-bonus.js | 9 +- module/rdd-combat.js | 249 ++++++++++++------ module/rdd-resolution-table.js | 6 +- module/rdd-tmr-dialog.js | 2 +- module/rdd-token-hud.js | 104 +++++--- module/roll/chat-roll-result.mjs | 65 +++-- module/roll/roll-basic-parts.mjs | 27 +- module/roll/roll-dialog-adapter.mjs | 80 ++++-- module/roll/roll-dialog.mjs | 33 +-- module/roll/roll-part-attaque.mjs | 17 +- module/roll/roll-part-defense.mjs | 7 +- module/roll/roll-type-attaque.mjs | 2 + module/roll/roll-type.mjs | 7 +- templates/actor/combat.hbs | 6 +- templates/actor/export-scriptarium/arme.hbs | 4 +- templates/chat-demande-defense-v1.hbs | 103 ++++++++ templates/chat-demande-defense.hbs | 150 ++++------- templates/chat-infojet.hbs | 8 +- templates/hud-actor-attaque.hbs | 4 +- templates/hud-actor-combat.hbs | 34 +++ templates/hud-actor-init.hbs | 10 +- templates/roll/result/chat-attaque.hbs | 75 ++++++ templates/roll/result/chat-defense.hbs | 17 +- templates/roll/result/chat-oeuvre.hbs | 1 - .../result/partial-attaque-particuliere.hbs | 16 ++ templates/roll/roll-part-attaque.hbs | 8 +- 44 files changed, 1033 insertions(+), 515 deletions(-) create mode 100644 assets/ui/part-finesse.svg create mode 100644 assets/ui/part-force.svg create mode 100644 assets/ui/part-rapidite.svg create mode 100644 templates/chat-demande-defense-v1.hbs create mode 100644 templates/hud-actor-combat.hbs create mode 100644 templates/roll/result/partial-attaque-particuliere.hbs diff --git a/assets/ui/part-finesse.svg b/assets/ui/part-finesse.svg new file mode 100644 index 00000000..b9fc0de7 --- /dev/null +++ b/assets/ui/part-finesse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/ui/part-force.svg b/assets/ui/part-force.svg new file mode 100644 index 00000000..15f4c4eb --- /dev/null +++ b/assets/ui/part-force.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/ui/part-rapidite.svg b/assets/ui/part-rapidite.svg new file mode 100644 index 00000000..dbb6d451 --- /dev/null +++ b/assets/ui/part-rapidite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/css/foundryvtt-reve-de-dragon.css b/css/foundryvtt-reve-de-dragon.css index c2740c49..15085962 100644 --- a/css/foundryvtt-reve-de-dragon.css +++ b/css/foundryvtt-reve-de-dragon.css @@ -655,7 +655,8 @@ select, width: 1.5rem; text-align: center; } -.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat { +.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat, +.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat { font-family: CaslonAntique; display: grid; grid-template-areas: "img header buttons" "img resume buttons" "details details details" "actions actions actions"; @@ -663,51 +664,61 @@ select, grid-template-rows: max-content max-content max-content max-content; gap: 0 0.5rem; } -.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-img { +.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-img, +.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-img { grid-area: img; display: flex; flex-direction: column; } -.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-img img { +.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-img img, +.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-img img { border: 0; max-height: 3rem; max-width: 3rem; object-fit: contain; height: 100%; } -.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-header { +.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-header, +.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-header { grid-area: header; font-weight: bold; font-size: 0.9rem; } -.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-resume { +.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-resume, +.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-resume { grid-area: resume; text-align: justify; } -.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-details { +.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-details, +.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-details { grid-area: details; text-align: justify; display: flex; flex-direction: column; } -.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions { +.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions, +.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-actions { grid-area: actions; display: flex; flex-direction: column; } -.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions a { +.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions a, +.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-actions a { display: flex; flex-direction: row; } -.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions a img { +.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions a img, +.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-actions a img { margin-right: 0.5rem; } -.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons { +.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons, +.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons { grid-area: buttons; display: flex; flex-direction: column; } -.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a { +.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a, +.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons a { border-radius: 0.2rem; cursor: pointer; padding: 0.2rem; @@ -718,14 +729,17 @@ select, display: inline-block; align-items: center; } -.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a img { +.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a img, +.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons a img { max-width: 1rem; max-height: 1rem; } -.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a:hover { +.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a:hover, +.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons a:hover { background: var(--background-custom-button-hover); } -.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a:active { +.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a:active, +.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons a:active { position: relative; top: 1px; } @@ -1975,14 +1989,18 @@ select, width: 9rem; height: fit-content; border-radius: 0.3rem; - min-width: 6rem; + min-width: 8rem; flex-basis: auto; padding: 0; - line-height: 0.95rem; + line-height: 1.6rem; margin: 0.2rem; + display: flex; + flex-direction: row; + align-items: center; } -.system-foundryvtt-reve-de-dragon .rdd-hud-menu label { - font-size: 0.8rem; +.system-foundryvtt-reve-de-dragon div.control-icon.token-hud-icon select, +.system-foundryvtt-reve-de-dragon div.control-icon.token-hud-icon label { + font-size: 1rem; } .system-foundryvtt-reve-de-dragon .item-checkbox { height: 25px; diff --git a/less/foundryvtt-reve-de-dragon.less b/less/foundryvtt-reve-de-dragon.less index 4d129e2a..975e0224 100644 --- a/less/foundryvtt-reve-de-dragon.less +++ b/less/foundryvtt-reve-de-dragon.less @@ -1341,14 +1341,18 @@ width: 9rem; height: fit-content; border-radius: 0.3rem; - min-width: 6rem; + min-width: 8rem; flex-basis: auto; padding: 0; - line-height: 0.95rem; + line-height: 1.6rem; margin: 0.2rem; - } - .rdd-hud-menu label { - font-size: 0.8rem; + + display: flex; + flex-direction: row; + align-items: center; + select, label { + font-size: 1rem; + } } /* ======================================== */ .item-checkbox { diff --git a/less/roll-chat.less b/less/roll-chat.less index c5da339c..69eb436e 100644 --- a/less/roll-chat.less +++ b/less/roll-chat.less @@ -1,87 +1,86 @@ -.chat-message { - div.roll-chat { - font-family: CaslonAntique; - display: grid; - grid-template-areas: - "img header buttons" - "img resume buttons" - "details details details" - "actions actions actions"; - grid-template-columns: 3rem 1fr 1.4rem; - grid-template-rows: max-content max-content max-content max-content; - gap: 0 0.5rem; +.chat-message div.roll-chat, +.dialog-content div.roll-chat { + font-family: CaslonAntique; + display: grid; + grid-template-areas: + "img header buttons" + "img resume buttons" + "details details details" + "actions actions actions"; + grid-template-columns: 3rem 1fr 1.4rem; + grid-template-rows: max-content max-content max-content max-content; + gap: 0 0.5rem; - div.chat-img { - grid-area: img; + div.chat-img { + grid-area: img; + display: flex; + flex-direction: column; + img { + border: 0; + max-height: 3rem; + max-width: 3rem; + object-fit: contain; + height: 100%; + } + } + div.chat-header { + grid-area: header; + font-weight: bold; + font-size: 0.9rem; + } + div.chat-resume { + grid-area: resume; + text-align: justify; + } + div.chat-details { + grid-area: details; + text-align: justify; + display: flex; + flex-direction: column; + } + div.chat-actions { + grid-area: actions; + display: flex; + flex-direction: column; + a { display: flex; - flex-direction: column; + flex-direction: row; img { - border: 0; - max-height: 3rem; - max-width: 3rem; - object-fit: contain; - height: 100%; + margin-right: 0.5rem; } } - div.chat-header { - grid-area: header; - font-weight: bold; - font-size: 0.9rem; - } - div.chat-resume { - grid-area: resume; - text-align: justify; - } - div.chat-details { - grid-area: details; - text-align: justify; - display: flex; - flex-direction: column; - } - div.chat-actions { - grid-area: actions; - display: flex; - flex-direction: column; - a { - display: flex; - flex-direction: row; - img { - margin-right: 0.5rem; - } + } + + div.chat-buttons { + grid-area: buttons; + display: flex; + flex-direction: column; + + a { + border-radius: 0.2rem; + cursor: pointer; + padding: 0.2rem; + position: relative; + box-shadow: inset 1x 1px #a6827e; + color: var(--color-controls); + border: 1px ridge #846109; + display: inline-block; + align-items: center; + + img { + max-width: 1rem; + max-height: 1rem; } } - div.chat-buttons { - grid-area: buttons; - display: flex; - flex-direction: column; - - a { - border-radius: 0.2rem; - cursor: pointer; - padding: 0.2rem; - position: relative; - box-shadow: inset 1x 1px #a6827e; - color: var(--color-controls); - border: 1px ridge #846109; - display: inline-block; - align-items: center; - - img { - max-width: 1rem; - max-height: 1rem; - } - } - - a:hover { - background: var(--background-custom-button-hover); - } - - a:active{ - position:relative; - top:1px; - } - + a:hover { + background: var(--background-custom-button-hover); } + + a:active{ + position:relative; + top:1px; + } + } -} \ No newline at end of file +} diff --git a/module/actor-token.mjs b/module/actor-token.mjs index 465e98e8..8a05ee30 100644 --- a/module/actor-token.mjs +++ b/module/actor-token.mjs @@ -2,6 +2,9 @@ * class providing the actor and token, and choosing the name and image from the token if available. */ export class ActorToken { + static fromTokenActor(token, actor){ + return token ? ActorToken.fromToken(token) : ActorToken.fromActor(actor) + } static fromActorId(actorId, onError = () => undefined) { actorId = actorId ?? (canvas.tokens.controlled.length > 0 diff --git a/module/actor.js b/module/actor.js index ec22cebe..1f4a34e1 100644 --- a/module/actor.js +++ b/module/actor.js @@ -136,12 +136,12 @@ export class RdDActor extends RdDBaseActorSang { } listActions({ isAttaque = false, isEquipe = false }) { - // Recupération des armes + // Recupération des attaques const actions = this.listActionsAttaque() .filter(it => !isEquipe || it.arme.system.equipe) if (!isAttaque && this.system.attributs.hautrevant.value) { - actions.push({ name: "Draconic", action: 'haut-reve', initOnly: true }) + actions.push({ label: "Draconic", action: 'haut-reve', initOnly: true }) } return actions } @@ -177,7 +177,7 @@ export class RdDActor extends RdDBaseActorSang { const actions = [] const uniques = [] - const addAttaque = (arme, main) => { + const addAttaque = (arme, main = undefined, action = 'attaque') => { const dommagesArme = RdDItemArme.valeurMain(arme.system.dommages, main) const forceRequise = RdDItemArme.valeurMain(arme.system.force ?? 0, main) const ecaillesEfficacite = arme.system.magique ? arme.system.ecaille_efficacite : 0; @@ -196,7 +196,7 @@ export class RdDActor extends RdDBaseActorSang { const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + ecaillesEfficacite actions.push({ - name: arme.name + (main ? ' ' + main : ''), + label: arme.name + (main ? ' ' + main : ''), action: 'attaque', initOnly: false, arme: arme, @@ -206,22 +206,23 @@ export class RdDActor extends RdDBaseActorSang { equipe: arme.system.equipe, dommagesArme: dommagesArme, forceRequise: forceRequise, - initiative: RdDInitiative.calculInitiative(niveau, caracValue, ajustement) + initiative: RdDInitiative.getRollInitiative(caracValue, niveau, ajustement) }) } - addAttaque(RdDItemArme.empoignade(this)) - addAttaque(RdDItemArme.corpsACorps(this)) - this.itemTypes[ITEM_TYPES.arme] .filter(it => it.isAttaque()) .sort(Misc.ascending(it => it.name)) .forEach(arme => { - if (arme.system.unemain && arme.system.competence) { addAttaque(arme, ATTAQUE_TYPE.UNE_MAIN) } - if (arme.system.deuxmains && arme.system.competence) { addAttaque(arme, ATTAQUE_TYPE.DEUX_MAINS) } - if (arme.system.lancer) { addAttaque(arme, ATTAQUE_TYPE.LANCER) } + if (arme.system.unemain && arme.system.competence && arme.system.resistance > 0) { addAttaque(arme, ATTAQUE_TYPE.UNE_MAIN) } + if (arme.system.deuxmains && arme.system.competence && arme.system.resistance > 0) { addAttaque(arme, ATTAQUE_TYPE.DEUX_MAINS) } + if (arme.system.lancer && arme.system.resistance > 0) { addAttaque(arme, ATTAQUE_TYPE.LANCER) } if (arme.system.tir) { addAttaque(arme, ATTAQUE_TYPE.TIR) } }) + + addAttaque(RdDItemArme.corpsACorps(this), ATTAQUE_TYPE.CORPS_A_CORPS) + addAttaque(RdDItemArme.empoignade(this), ATTAQUE_TYPE.CORPS_A_CORPS, 'empoignade') + return actions } diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index 6e5ab325..44c14571 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -25,6 +25,8 @@ import { RdDPossession } from "../rdd-possession.js"; import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, POSSESSION_SANS_DRACONIC } from "../item/base-items.js"; import { RollDataAjustements } from "../rolldata-ajustements.js"; import { MappingCreatureArme } from "../item/mapping-creature-arme.mjs"; +import RollDialog from "../roll/roll-dialog.mjs"; +import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_COMP, ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_OEUVRE, ROLL_TYPE_TACHE } from "../roll/roll-constants.mjs"; /** * Classe de base pour les acteurs disposant de rêve (donc, pas des objets) @@ -407,6 +409,20 @@ export class RdDBaseActorReve extends RdDBaseActor { } /* -------------------------------------------- */ + async rollCompetenceV2(rollData) { + foundry.utils.mergeObject(rollData, { + ids: { + actorId: this.id + }, + type: { + allowed: [ROLL_TYPE_COMP, ROLL_TYPE_OEUVRE, ROLL_TYPE_TACHE, ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION], + + } + }) + rollData.ids.actorId = rollData.ids.actorId ?? this.id + await RollDialog.create(rollData) + } + async rollCompetence(idOrName, options = { tryTarget: true, arme: undefined }) { RdDEmpoignade.checkEmpoignadeEnCours(this) const competence = this.getCompetence(idOrName); @@ -449,6 +465,46 @@ export class RdDBaseActorReve extends RdDBaseActor { } } + rollAttaque(token) { + token = token ?? RdDUtility.getSelectedToken(this) + + if (Targets.hasTargets()) { + Targets.selectOneTargetToken(target => { + if (Targets.isTargetEntite(target)) { + ui.notifications.warn(`Vous ne pouvez pas attaquer une entité non incarnée!!!!`) + return + } + + RdDCombat.rddCombatTarget(target, this, token).attaqueV2(); + }) + } + else { + return RdDConfirm.confirmer({ + settingConfirmer: "confirmer-combat-sans-cible", + content: `

Voulez vous faire une attaque sans choisir de cible valide? +
Tous les jets de combats devront être gérés à la main +

`, + title: 'Ne pas utiliser les automatisation de combat', + buttonLabel: "Pas d'automatisation", + onAction: async () => { + this.rollCompetenceV2({ + ids: { + actorId: this.id, + actorTokenId: token?.id, + }, + selected: { + conditions: { value: 0 } + }, + type: { + allowed: [ROLL_TYPE_COMP, ROLL_TYPE_ATTAQUE, ROLL_TYPE_OEUVRE, ROLL_TYPE_TACHE, ROLL_TYPE_JEU], + current: ROLL_TYPE_COMP + } + }) + } + }) + } + } + /** -------------------------------------------- * @param {*} arme item d'arme/compétence de créature * @param {*} categorieArme catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession diff --git a/module/actor/base-actor-sang.js b/module/actor/base-actor-sang.js index c80ba39d..7eeede7b 100644 --- a/module/actor/base-actor-sang.js +++ b/module/actor/base-actor-sang.js @@ -34,17 +34,17 @@ export class RdDBaseActorSang extends RdDBaseActorReve { getFatigueActuelle() { if (ReglesOptionnelles.isUsing("appliquer-fatigue")) { - return Math.max(0, Math.min(this.getFatigueMax(), Misc.toInt(this.system.sante.fatigue?.value))) + return Math.max(0, Math.min(this.getFatigueMax(), Misc.toInt(this.system.sante.fatigue?.value))) } return 0; } - isCumulFatigueCauseSommeil(cumulFatigue){ + isCumulFatigueCauseSommeil(cumulFatigue) { return ReglesOptionnelles.isUsing("appliquer-fatigue") - ? (this.getFatigueRestante() <= cumulFatigue) - : (this.getEnduranceActuelle() <= cumulFatigue) + ? (this.getFatigueRestante() <= cumulFatigue) + : (this.getEnduranceActuelle() <= cumulFatigue) } - getFatigueRestante() {return this.getFatigueMax() - this.getFatigueActuelle() } + getFatigueRestante() { return this.getFatigueMax() - this.getFatigueActuelle() } getFatigueMin() { return this.system.sante.endurance.max - this.system.sante.endurance.value } malusFatigue() { @@ -195,7 +195,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve { const endActuelle = this.getEnduranceActuelle(); const blessure = await RdDItemBlessure.createBlessure(this, encaissement.gravite, encaissement.dmg?.loc.label ?? '', attackerToken); if (blessure.isCritique()) { - encaissement.endurance = endActuelle; + encaissement.endurance = endActuelle } if (blessure.isMort()) { diff --git a/module/actor/base-actor-sheet.js b/module/actor/base-actor-sheet.js index 779b5f88..bdbca38f 100644 --- a/module/actor/base-actor-sheet.js +++ b/module/actor/base-actor-sheet.js @@ -56,10 +56,8 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet { this._appliquerRechercheObjets(formData.conteneurs, formData.inventaires); formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs); formData.competences.filter(it => it.type == ITEM_TYPES.competencecreature) - .forEach(it => { - const competenceCreature = new RdDItemCompetenceCreature(it.toObject(), { parent: it.parent }); - it.isdommages = competenceCreature.isDommages(); - }) + .forEach(it => it.isdommages = it.isDommages() + ) return formData; } diff --git a/module/actor/base-actor.js b/module/actor/base-actor.js index 2d3ca6f9..18cc9640 100644 --- a/module/actor/base-actor.js +++ b/module/actor/base-actor.js @@ -769,11 +769,15 @@ export class RdDBaseActor extends Actor { return this.itemTypes[ITEM_TYPES.possession] .map(p => { return { - name: p.name, + label: p.name, action: 'possession', possessionid: p.system.possessionid, } }) } - + listActionsCombat() { + const possessions = this.listActionsPossessions() + return possessions.length > 0 ? possessions : this.listActions({}) + + } } \ No newline at end of file diff --git a/module/constants.js b/module/constants.js index 201cd882..7bfb3481 100644 --- a/module/constants.js +++ b/module/constants.js @@ -12,16 +12,16 @@ export const ENTITE_BLURETTE = 'blurette' export const renderTemplate = foundry.applications.handlebars.renderTemplate export const RDD_CONFIG = { - niveauEthylisme : [ - {value: "1", label: "Aucun"}, - {value: "0", label: "Eméché (0)"}, - {value: "-1", label: "Gris (-1)"}, - {value: "-2", label: "Pinté (-2)"}, - {value: "-3", label: "Pas Frais (-3)"}, - {value: "-4", label: "Ivre (-4)"}, - {value: "-5", label: "Bu (-5)"}, - {value: "-6", label: "Complètement fait (-6)"}, - {value: "-7", label: "Ivre mort (-7)"} + niveauEthylisme: [ + { value: "1", label: "Aucun" }, + { value: "0", label: "Eméché (0)" }, + { value: "-1", label: "Gris (-1)" }, + { value: "-2", label: "Pinté (-2)" }, + { value: "-3", label: "Pas Frais (-3)" }, + { value: "-4", label: "Ivre (-4)" }, + { value: "-5", label: "Bu (-5)" }, + { value: "-6", label: "Complètement fait (-6)" }, + { value: "-7", label: "Ivre mort (-7)" } ], categorieEntite: { "cauchemar": "Cauchemar", @@ -32,28 +32,34 @@ export const RDD_CONFIG = { "nonincarne": "Non Incarnée", "blurette": "Blurette" }, - heuresRdD : [ - {value : "vaisseau", label: "Vaisseau", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd01.webp"}, - {value : "sirene", label: "Sirène", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd02.webp"}, - {value : "faucon", label: "Faucon", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd03.webp"}, - {value : "couronne", label: "Couronne", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd04.webp"}, - {value : "dragon", label: "Dragon", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd05.webp"}, - {value : "epees", label: "Epées", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd06.webp"}, - {value : "lyre", label: "Lyre", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd07.webp"}, - {value : "serpent", label: "Serpent", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd08.webp"}, - {value : "poissonacrobate", label: "Poisson Acrobate", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd09.webp"}, - {value : "araignee", label: "Araignée", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd10.webp"}, - {value : "roseau", label: "Roseau", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd11.webp"}, - {value : "chateaudormant", label: "Chateau Dormant", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd12.webp"} + heuresRdD: [ + { value: "vaisseau", label: "Vaisseau", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd01.webp" }, + { value: "sirene", label: "Sirène", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd02.webp" }, + { value: "faucon", label: "Faucon", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd03.webp" }, + { value: "couronne", label: "Couronne", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd04.webp" }, + { value: "dragon", label: "Dragon", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd05.webp" }, + { value: "epees", label: "Epées", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd06.webp" }, + { value: "lyre", label: "Lyre", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd07.webp" }, + { value: "serpent", label: "Serpent", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd08.webp" }, + { value: "poissonacrobate", label: "Poisson Acrobate", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd09.webp" }, + { value: "araignee", label: "Araignée", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd10.webp" }, + { value: "roseau", label: "Roseau", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd11.webp" }, + { value: "chateaudormant", label: "Chateau Dormant", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd12.webp" } ], raretes: [ - {value: "Commune", label: "Commune"}, - {value: "Frequente", label: "Fréquente"}, - {value: "Rare", label: "Rare"}, - {value: "Rarissime", label: "Rarissime"} - ] + { value: "Commune", label: "Commune" }, + { value: "Frequente", label: "Fréquente" }, + { value: "Rare", label: "Rare" }, + { value: "Rarissime", label: "Rarissime" } + ], + particuliere: { + force: { key: 'force', descr: 'en force', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-force.svg'}, + finesse: { key: 'finesse', descr: 'en finesse', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-finesse.svg'}, + rapidite: { key: 'finesse', descr: 'en rapidité', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-rapidite.svg'}, + } } + export const ACTOR_TYPES = { personnage: 'personnage', creature: 'creature', @@ -109,13 +115,3 @@ export const ITEM_TYPES = { extraitpoetique: 'extraitpoetique', } -export const CATEGORIES_COMPETENCES = { - "generale": { base: -4, label: "Générales" }, - "particuliere": { base: -8, label: "Particulières" }, - "specialisee": { base: -11, label: "Spécialisées" }, - "connaissance": { base: -11, label: "Connaissances" }, - "draconic": { base: -11, label: "Draconic" }, - "melee": { base: -6, label: "Mêlée" }, - "tir": { base: -8, label: "Tir" }, - "lancer": { base: -8, label: "Lancer" } -} diff --git a/module/initiative.mjs b/module/initiative.mjs index eedf6978..4ddf5c10 100644 --- a/module/initiative.mjs +++ b/module/initiative.mjs @@ -1,7 +1,65 @@ +export const MAP_PHASE = { + possession: { label: "possession", rang: 10 }, + draconic: { label: "draconic", rang: 9 }, + tir: { label: "tir", rang: 8 }, + lancer: { label: "lancer", rang: 7 }, + arme: { label: "mêlée", rang: 5 }, + pugilat: { label: "pugilat", rang: 4 }, + naturelle: { label: "créature", rang: 4 }, + empoignade: { label: "empoignade", rang: 3 }, + autre: { label: "autre action", rang: 2 }, + demi: { label: "demi-surprise", rang: 0 }, + totale: { label: "surprise totale", rang: -1 }, +} +export const PHASE = Object.values(MAP_PHASE) + export class RdDInitiative { - static calculInitiative(niveau, caracValue, bonus = 0) { - let base = niveau + Math.floor(caracValue / 2) + bonus; - return "1d6" + (base >= 0 ? "+" : "") + base; + static getRollInitiative(caracValue, niveau, bonus = 0) { + const base = RdDInitiative.ajustementInitiative(caracValue, niveau, bonus) + return "1d6" + (base >= 0 ? "+" : "") + base + } + + static ajustementInitiative(caracValue, niveau, bonus) { + return niveau + Math.floor(caracValue / 2) + bonus + } + + static formule(phase, carac, niveau, bonusMalus) { + const ajustement = RdDInitiative.ajustementInitiative(carac, niveau, bonusMalus) + return { phase, ajustement } + } + + static phaseArme(categorie, arme) { + switch (categorie) { + case "tir": + case "lancer": + return MAP_PHASE[categorie] + default: + switch (arme.system.cac) { + case "empoignade": + case "pugilat": + case "naturelle": + return MAP_PHASE[arme.system.cac] + default: + return MAP_PHASE['arme'] + } + } + } + + static phase(keyOrRang) { + return MAP_PHASE[keyOrRang] ?? PHASE.find(it => it.rang == keyOrRang) ?? MAP_PHASE.autre + } + + static async roll(formule) { + const sign = formule.ajustement >= 0 ? "+" : "" + const roll = new Roll(`1d6 + ${sign} + ${formule.ajustement}`) + await roll.evaluate() + const value = Math.max(roll.total, 0) + return { + roll: roll, + value: value, + init: formule.phase.rang + value / 100, + label: formule.phase.label + } } } diff --git a/module/item-competencecreature.js b/module/item-competencecreature.js index d39c29fb..35519b3f 100644 --- a/module/item-competencecreature.js +++ b/module/item-competencecreature.js @@ -10,15 +10,15 @@ export class RdDItemCompetenceCreature extends RdDItem { static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp" } + isAttaque() { return this.getCategorieAttaque() != undefined } isParade() { return this.system.iscombat && (this.system.categorie_parade ?? '') != '' } isBouclier() { return this.system.categorie_parade.includes('bouclier') } - attaqueCreature() { const categorieAttaque = this.getCategorieAttaque() if (categorieAttaque != undefined) { - const initative = RdDInitiative.calculInitiative(this.system.niveau, this.system.carac_value); + const initative = RdDInitiative.getRollInitiative(this.system.carac_value, this.system.niveau); const attaque = { - name: this.name, + label: this.name, action: this.isCompetencePossession() ? 'possession' : 'attaque', initOnly: false, arme: new RdDItemArme({ @@ -51,10 +51,6 @@ export class RdDItemCompetenceCreature extends RdDItem { return undefined; } - isAttaque() { - return this.getCategorieAttaque() != undefined - } - getCategorieAttaque() { switch (this.system.categorie) { case "melee": diff --git a/module/item/arme.js b/module/item/arme.js index 293ec226..fc4f995a 100644 --- a/module/item/arme.js +++ b/module/item/arme.js @@ -21,6 +21,7 @@ const nomCategorieParade = { export const ATTAQUE_TYPE = { UNE_MAIN: '(1 main)', DEUX_MAINS: '(2 mains)', + CORPS_A_CORPS: '(corps à corps)', COMPETENCE: 'competence', TIR: '(tir)', LANCER: '(lancer)' @@ -244,7 +245,7 @@ export class RdDItemArme extends RdDItem { } isAttaque() { - return this.system.resistance > 0 || this.system.portee_courte > 0 + return this.system.resistance > 0 || (this.system.tir != '' && this.system.portee_courte > 0) } static corpsACorps(actor) { @@ -256,7 +257,7 @@ export class RdDItemArme extends RdDItem { type: ITEM_TYPES.arme, img: competence.img, system: { - initiative: RdDInitiative.calculInitiative(competence.system.niveau, melee), + initiative: RdDInitiative.getRollInitiative(melee, competence.system.niveau), equipe: true, rapide: true, force: 0, @@ -273,10 +274,10 @@ export class RdDItemArme extends RdDItem { }) } - static mainsNues(actor) { - const mainsNues = RdDItemArme.corpsACorps(actor) - mainsNues.name = 'Mains nues' - return mainsNues; + static pugilat(actor) { + const pugilat = RdDItemArme.corpsACorps(actor) + pugilat.name = 'Mains nues' + return pugilat; } static empoignade(actor) { diff --git a/module/item/mapping-creature-arme.mjs b/module/item/mapping-creature-arme.mjs index a643b6b9..92a73cc1 100644 --- a/module/item/mapping-creature-arme.mjs +++ b/module/item/mapping-creature-arme.mjs @@ -3,7 +3,6 @@ import { RdDInitiative } from "../initiative.mjs"; export class MappingCreatureArme { - /* -------------------------------------------- */ static setRollDataCreature(rollData) { const code = Grammar.toLowerCaseNoAccentNoSpace(rollData.competence.name); @@ -26,7 +25,7 @@ export class MappingCreatureArme { competence: item.name, cac: categorieAttaque == "naturelle" ? "naturelle" : "", niveau: item.system.niveau, - initiative: RdDInitiative.calculInitiative(item.system.niveau, item.system.carac_value), + initiative: RdDInitiative.getRollInitiative(item.system.carac_value, item.system.niveau), equipe: true, resistance: 100, dommagesReels: item.system.dommages, diff --git a/module/misc.js b/module/misc.js index ac0e933a..2a62683c 100644 --- a/module/misc.js +++ b/module/misc.js @@ -34,9 +34,13 @@ export class Misc { return ((n % m) + m) % m; } - static inRange(value, min,max){ + static inRange(value, min, max) { + if (min > max) { + return Misc.inRange(value, max, min) + } return Math.max(min, Math.min(value, max)) } + static sum() { return (a, b) => Number(a) + Number(b); } @@ -111,6 +115,10 @@ export class Misc { list.forEach(it => addToObj(obj, it)) return obj; } + static indexed(list, index = 'index') { + let i = 0; + return list.map(it => { it[index] = i++; return it }) + } static concat(lists) { return lists.reduce((a, b) => a.concat(b), []); diff --git a/module/rdd-bonus.js b/module/rdd-bonus.js index f8a9d969..8b8fd600 100644 --- a/module/rdd-bonus.js +++ b/module/rdd-bonus.js @@ -56,9 +56,8 @@ export class RdDBonus { return dmg; } - static dmgRollV2(rollData, current) { + static dmgRollV2(rollData, attaque) { const actor = rollData.active.actor - const attaque = current.attaque const arme = attaque.arme const dmgArme = RdDBonus.dmgArme(arme, attaque.dommagesArme) const dmg = { @@ -66,10 +65,10 @@ export class RdDBonus { dmgArme: dmgArme, penetration: arme.penetration(), diff: attaque.diff, - dmgTactique: current.tactique?.dmg ?? 0, - dmgParticuliere: 0, // TODO RdDBonus._dmgParticuliere(rollData), + dmgTactique: attaque.tactique?.dmg ?? 0, + dmgParticuliere: RdDBonus._dmgParticuliere(rollData), dmgSurprise: rollData.opponent?.surprise?.dmg ?? 0, - mortalite: RdDBonus.mortalite(current.dmg?.mortalite, arme.system.mortalite, rollData.opponent?.actor?.isEntite()), + mortalite: RdDBonus.mortalite(attaque.dmg?.mortalite, arme.system.mortalite, rollData.opponent?.actor?.isEntite()), dmgActor: RdDBonus.bonusDmg(actor, attaque.carac.key, dmgArme, attaque.forceRequise), dmgForceInsuffisante: Math.min(0, actor.getForce() - attaque.forceRequise), dmgDiffLibre: ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(attaque.diff ?? 0) : 0 diff --git a/module/rdd-combat.js b/module/rdd-combat.js index ef5a4bc1..cdf0ba56 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -12,13 +12,14 @@ import { RdDEmpoignade } from "./rdd-empoignade.js"; import { RdDRollResult } from "./rdd-roll-result.js"; import { RdDItemArme } from "./item/arme.js"; import { RdDItemCompetence } from "./item-competence.js"; -import { RdDInitiative } from "./initiative.mjs"; +import { MAP_PHASE, RdDInitiative } from "./initiative.mjs"; import RollDialog from "./roll/roll-dialog.mjs"; import { PART_DEFENSE } from "./roll/roll-part-defense.mjs"; import { RollDialogAdapter } from "./roll/roll-dialog-adapter.mjs"; import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll/roll-constants.mjs"; import { OptionsAvancees, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js"; import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs"; +import { RollBasicParts } from "./roll/roll-basic-parts.mjs"; /* -------------------------------------------- */ const premierRoundInit = [ @@ -67,7 +68,7 @@ export class RdDCombatManager extends Combat { if (Misc.isFirstConnectedGM()) { await this.finDeRound({ terminer: true }) ChatUtility.removeChatMessageContaining(`
`) - game.messages.filter(m => ChatUtility.getMessageData(m, 'attacker-roll') != undefined && ChatUtility.getMessageData(m, 'defender-roll') != undefined) + game.messages.filter(m => ChatUtility.getMessageData(m, 'rollData') != undefined && ChatUtility.getMessageData(m, 'rollData') != undefined) .forEach(it => it.delete()) RdDEmpoignade.deleteAllEmpoignades() } @@ -106,13 +107,15 @@ export class RdDCombatManager extends Combat { return combatant.actor } - static calculAjustementInit(actor, arme) { - const efficacite = (arme?.system.magique) ? arme.system.ecaille_efficacite : 0 - const etatGeneral = actor.getEtatGeneral() ?? 0 - return efficacite + etatGeneral - + static bonusArme(arme) { + return (arme?.system.magique) ? arme.system.ecaille_efficacite : 0 } + static etatGeneral(actor) { + return actor.getEtatGeneral() ?? 0; + } + + /************************************************************************************/ async rollInitiative(ids, messageOptions = {}) { console.log(`${game.system.title} | Combat.rollInitiative()`, ids, messageOptions) @@ -121,18 +124,17 @@ export class RdDCombatManager extends Combat { return this } - async rollInitRdD(id, formula, messageOptions = {}) { + async rollInitRdD(id, formule, messageOptions = {}) { const combatant = this.combatants.get(id); const actor = RdDCombatManager.getActorCombatant(combatant) if (actor) { - const rollFormula = formula ?? RdDCombatManager.getFirstInitRollFormula(actor) - const roll = combatant.getInitiativeRoll(rollFormula); - if (!roll.total) { - await roll.evaluate(); - } - const total = Math.max(roll.total, 0.00); - console.log("Compute init for", rollFormula, roll, total, combatant); - await this.updateEmbeddedDocuments("Combatant", [{ _id: combatant._id || combatant.id, initiative: total }]); + formule = formule ?? RdDCombatManager.getFirstInitRollFormula(actor) + const init = await RdDInitiative.roll(formule) + + await this.updateEmbeddedDocuments("Combatant", [{ + _id: combatant._id || combatant.id, + initiative: init.init, 'system.init': init + }]) // Send a chat message let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode"); @@ -147,7 +149,7 @@ export class RdDCombatManager extends Combat { flavor: `${combatant.token?.name} a fait son jet d'Initiative (${messageOptions.info})
` }, messageOptions); - roll.toMessage(messageData, { rollMode, create: true }); + init.roll.toMessage(messageData, { rollMode, create: true }); RdDCombatManager.processPremierRoundInit(); } @@ -159,16 +161,11 @@ export class RdDCombatManager extends Combat { if (actions.length > 0) { const action = actions[0] const init = RdDCombatManager.getInitData(actor, action) - const ajustement = RdDCombatManager.calculAjustementInit(actor, action) - return RdDCombatManager.formuleInitiative(init.offset, init.carac, init.niveau, ajustement); + const ajustement = RdDCombatManager.bonusArme(action.arme) + RdDCombatManager.etatGeneral(actor) + return RdDInitiative.formule(init.phase, init.carac, init.niveau, ajustement); } - let ajustement = RdDCombatManager.calculAjustementInit(actor, undefined); - return RdDCombatManager.formuleInitiative(2, 10, 0, ajustement); - } - - static formuleInitiative(rang, carac, niveau, bonusMalus) { - return `${rang} +( (${RdDInitiative.calculInitiative(niveau, carac, bonusMalus)} )/100)`; + return RdDInitiative.formule(MAP_PHASE['autre'], 10, 0, actor.getEtatGeneral() ?? 0); } /* -------------------------------------------- */ @@ -180,7 +177,6 @@ export class RdDCombatManager extends Combat { for (let combatant of game.combat.combatants) { if (combatant.initiativeData?.arme?.type == "arme") { // TODO: get init data premier round - const initiativeData = combatant.initiativeData; const action = combatant.initiativeData.arme; const fromArme = Grammar.toLowerCaseNoAccentNoSpace(action.system.initpremierround) const initData = premierRoundInit.find(it => fromArme.includes(initData.pattern)) @@ -200,10 +196,27 @@ export class RdDCombatManager extends Combat { } /* -------------------------------------------- */ - static incDecInit(combatantId, incDecValue) { - const combatant = game.combat.combatants.get(combatantId); - let initValue = combatant.initiative + incDecValue; - game.combat.setInitiative(combatantId, initValue); + + static applyInitiativeCommand(combatantId, command, commandValue) { + switch (command) { + case 'delta': return RdDCombatManager.incDecInit(combatantId, commandValue); + case 'autre': return RdDCombatManager.rollInitiativeAction(combatantId, + { name: "Autre action", action: 'autre', system: { initOnly: true, competence: "Autre action" } }); + } + } + + static async incDecInit(combatantId, incDecValue) { + const combatant = game.combat.combatants.get(combatantId) + if (combatant?.initiative && incDecValue != 0) { + const value = combatant.system.init.value + incDecValue + const newInit = combatant.initiative + incDecValue / 100; + await game.combat.updateEmbeddedDocuments("Combatant", [{ + _id: combatantId, + initiative: newInit, + 'system.init.value': value, + 'system.init.init': newInit, + }]) + } } /* -------------------------------------------- */ @@ -220,56 +233,42 @@ export class RdDCombatManager extends Combat { } } options = [ - { name: "Incrémenter initiative", condition: true, icon: '', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), +0.01); } }, - { name: "Décrémenter initiative", condition: true, icon: '', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), -0.01); } } + { name: "Incrémenter initiative", condition: true, icon: '', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), +1); } }, + { name: "Décrémenter initiative", condition: true, icon: '', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), -1); } } ].concat(options); } + /* -------------------------------------------- */ static async rollInitiativeAction(combatantId, action) { const combatant = game.combat.combatants.get(combatantId) const actor = RdDCombatManager.getActorCombatant(combatant) - if (actor == undefined) { return [] } - combatant.initiativeData = { arme: action } // pour reclasser l'init au round 0 + if (actor == undefined) { return } const init = RdDCombatManager.getInitData(actor, action) - const ajustement = RdDCombatManager.calculAjustementInit(actor, action.arme) - const rollFormula = RdDCombatManager.formuleInitiative(init.offset, init.carac, init.niveau, ajustement); + const ajustement = RdDCombatManager.bonusArme(actor, action.arme) + RdDCombatManager.etatGeneral(actor) + const formule = RdDInitiative.formule(init.phase, init.carac, init.niveau, ajustement); - await game.combat.rollInitRdD(combatantId, rollFormula, init); - combatant.initiativeData + await game.combat.rollInitRdD(combatantId, formule, init); + combatant.initiativeData = { action, formule } // pour reclasser l'init au round 0 } static getInitData(actor, action) { - if (actor.getSurprise() == "totale") { return { offset: -1, info: "Surprise Totale", carac: 0, niveau: 0 } } - if (actor.getSurprise() == "demi") { return { offset: 0, info: "Demi Surprise", carac: 0, niveau: 0 } } - if (action.action == 'autre') { return { offset: 2, info: "Autre Action", carac: 0, niveau: 0 } } - if (action.action == 'possession') { return { offset: 10, info: "Possession", carac: actor.getReveActuel(), niveau: 0 } } - if (action.action == 'haut-reve') { return { offset: 9, info: "Draconic", carac: actor.getReveActuel(), niveau: 0 } } + if (actor.getSurprise() == "totale") { return { phase: MAP_PHASE['totale'], info: "Surprise Totale", carac: 0, niveau: 0 } } + if (actor.getSurprise() == "demi") { return { phase: MAP_PHASE['demi'], info: "Demi Surprise", carac: 0, niveau: 0 } } + if (action.action == 'autre') { return { phase: MAP_PHASE['autre'], info: "Autre Action", carac: 0, niveau: 0 } } + if (action.action == 'possession') { return { phase: MAP_PHASE['possession'], info: "Possession", carac: actor.getReveActuel(), niveau: 0 } } + if (action.action == 'haut-reve') { return { phase: MAP_PHASE['draconic'], info: "Draconic", carac: actor.getReveActuel(), niveau: 0 } } const comp = action.comp return { - offset: RdDCombatManager.initOffset(comp?.system.categorie, action.arme), + phase: RdDInitiative.phaseArme(comp?.system.categorie, action.arme), info: action.name + " / " + comp.name, carac: actor.getCaracInit(comp), niveau: comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(action.main) ? -8 : -6) } } - static initOffset(categorie, arme) { - switch (categorie) { - case "tir": return 8 - case "lancer": return 7 - default: - switch (arme.system.cac) { - case "empoignade": return 3 - case "pugilat": return 4 - case "naturelle": return 4 - default: return 5 - } - } - } - /* -------------------------------------------- */ static displayInitiativeMenu(html, combatantId) { const combatant = game.combat.combatants.get(combatantId) @@ -297,13 +296,8 @@ export class RdDCombatManager extends Combat { ? possessions : actor.listActions({ isEquipe: true }) - for (let index = 0; index < actions.length; index++) { - actions[index].index = index - } - return actions + return Misc.indexed(actions) } - - } /* -------------------------------------------- */ @@ -383,8 +377,13 @@ export class RdDCombat { let defenderToken = canvas.tokens.get(msg.defenderToken.id) if (defenderToken && Misc.isFirstConnectedGM()) { const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id) - rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme) - rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll) + rddCombat?.removeChatMessageActionsPasseArme(msg.paramChatDefense.attackerRoll.passeArme) + if (msg.defenderRoll.ids) {/* TODO: delete roll V1 */ + RollDialog.loadRollData(msg.paramChatDefense) + rddCombat?._chatMessageDefenseV2(msg.paramChatDefense) + } else { + rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll) + } } } @@ -464,8 +463,8 @@ export class RdDCombat { /* -------------------------------------------- */ async onEvent(button, event) { const chatMessage = ChatUtility.getChatMessage(event); - const defenderRoll = ChatUtility.getMessageData(chatMessage, 'defender-roll'); - const attackerRoll = defenderRoll?.attackerRoll ?? ChatUtility.getMessageData(chatMessage, 'attacker-roll'); + const defenderRoll = ChatUtility.getMessageData(chatMessage, 'rollData'); + const attackerRoll = defenderRoll?.attackerRoll ?? ChatUtility.getMessageData(chatMessage, 'rollData'); console.log('RdDCombat', attackerRoll, defenderRoll); const armeParadeId = event.currentTarget.attributes['data-armeid']?.value; @@ -665,6 +664,92 @@ export class RdDCombat { 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 + } + await this.doRollAttaque({ + ids: { + actorId: this.attackerId, + actorTokenId: this.attackerTokenId, + opponentId: this.defender.id, + opponentTokenId: this.defenderTokenId, + }, + type: { allowed: ['attaque'], current: 'attaque' }, + passeArme: foundry.utils.randomID(16), + }) + } + + async doRollAttaque(rollData, callbacks = []) { + // TODO V2 await this.proposerAjustementTirLancer(rollData) + await RollDialog.create(rollData, { + onRollDone: (dialog) => { + if (!OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST)) + dialog.close() + }, + customChatMessage: true, + callbacks: [ + async (roll) => await this.onAttaqueV2(roll), + ...callbacks + ] + }) + } + + async onAttaqueV2(attackerRoll) { + if (!this.defender || !attackerRoll.rolled.isSuccess || attackerRoll.particulieres?.length > 1) { + return + } + if (!await this.attacker.accorder(this.defender, 'avant-defense')) { + return; + } + + RollDialog.loadRollData(attackerRoll) + + const surpriseDefender = this.defender.getSurprise(true); + const paramChatDefense = { + attackerRoll: attackerRoll, + isPossession: this.isPossession(attackerRoll), + defender: this.defender, + attacker: this.attacker, + attackerId: this.attackerId, + attackerToken: this.attackerToken, + defenderToken: this.defenderToken, + surprise: surpriseDefender, + } + + if (Misc.isFirstConnectedGM()) { + await this._chatMessageDefenseV2(paramChatDefense); + } + else { + this._socketSendMessageDefense(paramChatDefense, {}); + } + } + async _chatMessageDefenseV2(paramDemandeDefense) { + const attackerRoll = paramDemandeDefense.attackerRoll; + RollBasicParts.loadSurprises(attackerRoll) + attackerRoll.passeArme = attackerRoll.passeArme ?? foundry.utils.randomID(16) + attackerRoll.dmg = RdDBonus.dmgRollV2(attackerRoll, attackerRoll.current.attaque) + // attackerRoll.current.attaque.dmg = attackerRoll.dmg + // attaque.dmg = attackerRoll.current.attaque.dmg + const attaque = RollDialog.saveParts(attackerRoll) + const defense = { + attackerRoll: attaque, + ids: RollBasicParts.reverseIds(attaque), + passeArme: attaque.passeArme ?? foundry.utils.randomID(16) + } + + const choixDefense = await ChatMessage.create({ + // message privé: du défenseur à lui même (et aux GMs) + speaker: ChatMessage.getSpeaker(this.defender, canvas.tokens.get(this.defenderTokenId)), + alias: this.attacker?.getAlias(), + whisper: ChatUtility.getOwners(this.defender), + content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.hbs', attackerRoll) + }); + // flag pour garder les jets d'attaque/defense + ChatUtility.setMessageData(choixDefense, 'rollData', defense) + } + /* -------------------------------------------- */ async attaque(competence, arme) { if (!await this.attacker.accorder(this.defender, 'avant-attaque')) { @@ -725,7 +810,7 @@ export class RdDCombat { // sans armes: à mains nues rollData.arme = RdDItemArme.corpsACorps(this.attacker) rollData.arme.system.niveau = competence.system.niveau - rollData.arme.system.initiative = RdDInitiative.calculInitiative(competence.system.niveau, this.attacker.system.carac['melee'].value); + rollData.arme.system.initiative = RdDInitiative.getRollInitiative(this.attacker.system.carac['melee'].value, competence.system.niveau); } return rollData; } @@ -776,7 +861,7 @@ export class RdDCombat { passeArme: rollData.passeArme }) }); - ChatUtility.setMessageData(choixParticuliere, 'attacker-roll', rollData); + ChatUtility.setMessageData(choixParticuliere, 'rollData', rollData); } /* -------------------------------------------- */ @@ -852,10 +937,10 @@ export class RdDCombat { speaker: ChatMessage.getSpeaker(this.defender, canvas.tokens.get(this.defenderTokenId)), alias: this.attacker?.getAlias(), whisper: ChatUtility.getOwners(this.defender), - content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.hbs', paramDemandeDefense), + content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense-v1.hbs', paramDemandeDefense), }); // flag pour garder les jets d'attaque/defense - ChatUtility.setMessageData(choixDefense, 'defender-roll', defenderRoll); + ChatUtility.setMessageData(choixDefense, 'rollData', defenderRoll); } /* -------------------------------------------- */ @@ -869,7 +954,7 @@ export class RdDCombat { defenderToken: this.defenderToken, defenderRoll: defenderRoll, paramChatDefense: paramChatDefense, - rollMode: true + rollMode: true, } }); } @@ -906,7 +991,7 @@ export class RdDCombat { essais: attackerRoll.essais }) }); - ChatUtility.setMessageData(choixEchecTotal, 'attacker-roll', attackerRoll); + ChatUtility.setMessageData(choixEchecTotal, 'rollData', attackerRoll); } /* -------------------------------------------- */ @@ -968,6 +1053,7 @@ export class RdDCombat { async defenseV2(attackerRoll) { // this._prepareParade(attackerRoll, arme, competence); + RollDialog.loadRollData(attackerRoll) await this.doRollDefense({ ids: { actorId: this.defender.id, @@ -1034,22 +1120,17 @@ export class RdDCombat { if (RdDCombat.isReussite(rollData)) { if (isParade) { await this.computeDeteriorationArme(rollData) + if (RdDCombat.isParticuliere(rollData)) { + await this.infoAttaquantDesarme(rollData) + } } - if (RdDCombat.isParticuliere(rollData)) { - await this._onDefenseParticuliere(rollData, isEsquive) - } } this.removeChatMessageActionsPasseArme(rollData.passeArme) } - async _onDefenseParticuliere(rollData, isEsquive) { - if (isEsquive) { - ChatUtility.createChatWithRollMode( - { content: "Vous pouvez esquiver une deuxième fois!" }, - this.defender) - } - else if (/*TODO: parade?*/!rollData.attackerRoll?.particuliere) { + async infoAttaquantDesarme(rollData) { + if (/*TODO: parade?*/!rollData.attackerRoll?.particuliere) { // TODO: attaquant doit jouer résistance et peut être désarmé p132 ChatUtility.createChatWithRollMode( { content: `(à gérer) L'attaquant doit jouer résistance et peut être désarmé (p132)` }, diff --git a/module/rdd-resolution-table.js b/module/rdd-resolution-table.js index 896b41b0..18c7545f 100644 --- a/module/rdd-resolution-table.js +++ b/module/rdd-resolution-table.js @@ -67,9 +67,9 @@ export class RdDResolutionTable { } /* -------------------------------------------- */ - static _computeCell(niveau, percentage) { + static _computeCell(level, percentage) { return { - niveau: niveau, + level: level, score: percentage, norm: Math.min(99, percentage), sign: this._reussiteSignificative(percentage), @@ -189,7 +189,7 @@ export class RdDResolutionTable { static computeReussite(chances, roll, diviseur) { const reussite = reussites.find(x => x.condition(chances, roll)) if (diviseur > 1 && reussite.isSuccess) { - if (chances > roll * diviseur) { + if (chances.norm < roll * diviseur) { return reussiteInsuffisante } } diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js index d6c77a4a..fbc88b7f 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -1,5 +1,5 @@ import { renderTemplate, SHOW_DICE, SYSTEM_RDD } from "./constants.js"; -import { RollDataAjustements } from "./rolldata-ajustements.js"; +import { RollDataAjustements } from "./rolldata-ajustements-v1.js"; import { RdDUtility } from "./rdd-utility.js"; import { COORD_TMR_INCONNU, TMRUtility } from "./tmr-utility.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js"; diff --git a/module/rdd-token-hud.js b/module/rdd-token-hud.js index 9fa182b3..f9612726 100644 --- a/module/rdd-token-hud.js +++ b/module/rdd-token-hud.js @@ -1,7 +1,9 @@ /* -------------------------------------------- */ import { renderTemplate } from "./constants.js"; import { HtmlUtility } from "./html-utility.js"; +import { Misc } from "./misc.js"; import { RdDCombatManager } from "./rdd-combat.js"; +import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js"; import { Targets } from "./targets.js"; /* -------------------------------------------- */ @@ -31,43 +33,86 @@ export class RdDTokenHud { const combatant = game.combat.combatants.find(c => c.tokenId == tokenId) const actor = RdDCombatManager.getActorCombatant(combatant, { warning: false }) if (actor) { - const actions = RdDCombatManager.listActionsActorCombatant(actor) - // initiative - await RdDTokenHud.addExtensionHudInit(html, combatant, actions) - // combat - await RdDTokenHud.addExtensionHudCombat(html, combatant, token, actions.filter(it => !it.initOnly)) + if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) { + await RdDTokenHud.addExtensionHudCombat(html, combatant, actor, token) + } + else { + const actions = RdDCombatManager.listActionsActorCombatant(actor) + // initiative + await RdDTokenHud.addExtensionHudInit(html, combatant, actions) + // combat + await RdDTokenHud.addExtensionHudAttaques(html, combatant, token, actions.filter(it => !it.initOnly)) + } } } + } + static async addExtensionHudCombat(html, combatant, actor, token) { + const actionsActor = actor.listActionsCombat(); + const ajustements = combatant?.initiative ? + [ + { label: 'Initiative +1', action: 'delta', value: 1 }, + { label: 'Initiative -1', action: 'delta', value: -1 } + ] : [] + const autres = [{ label: "Autre action", action: 'autre' }] + const actions = Misc.indexed(actionsActor.concat(ajustements).concat(autres)) + const hudData = { combatant, token, actions }; + const hud = $(await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/hud-actor-combat.hbs', hudData)) + $(html).find('div.col.left').append(hud) + + const list = hud.find('div.rdd-hud-list') + RdDTokenHud.setupHudToggle(hud, list) + + const selectInitiative = list.find('select[name="initiative"]'); + selectInitiative.change(event => { + const action = actions.find(it => it.index == event.currentTarget.value) + console.log('select initiative', combatant.id, action) + if (action) { + switch (action.action) { + case 'delta': + RdDCombatManager.incDecInit(combatant.id, action.value); + break + case 'autre': + RdDCombatManager.rollInitiativeAction(combatant.id, + { label: "Autre action", action: 'autre', system: { initOnly: true, competence: "Autre action" } }); + break + default: + RdDCombatManager.rollInitiativeAction(combatant.id, action) + } + selectInitiative.select("") + } + }) + list.find('.rdd-attaque-v2').click(event => combatant.actor.rollAttaque(token)) } static async addExtensionHudInit(html, combatant, actions) { const hudData = { combatant, actions, commandes: [ - { name: "Autre action", command: 'autre' }, - { name: 'Initiative +1', command: 'inc', value: 0.01 }, - { name: 'Initiative -1', command: 'dec', value: -0.01 }] + { label: "Autre action", command: 'autre' }, + { label: 'Initiative +1', command: 'delta', value: 1 }, + { label: 'Initiative -1', command: 'deltac', value: -1 }] }; const controlIconCombat = $(html).find('.control-icon[data-action=combat]'); await RdDTokenHud._configureSubMenu(it => controlIconCombat.after(it), 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.hbs', hudData, (event) => { - let initCommand = event.currentTarget.attributes['data-command']?.value; - let combatantId = event.currentTarget.attributes['data-combatant-id']?.value; + let initCommand = event.currentTarget.attributes['data-command']?.value + let initCommandValue = Number(event.currentTarget.attributes['data-command-value']?.value ?? 0) + let combatantId = event.currentTarget.attributes['data-combatant-id']?.value if (initCommand) { - RdDTokenHud._initiativeCommand(initCommand, combatantId); + RdDCombatManager.applyInitiativeCommand(combatantId, initCommand, initCommandValue) } else { - let index = event.currentTarget.attributes['data-action-index'].value; - let action = hudData.actions[index]; - RdDCombatManager.rollInitiativeAction(combatantId, action); + let index = event.currentTarget.attributes['data-action-index'].value + let action = hudData.actions[index] + RdDCombatManager.rollInitiativeAction(combatantId, action) } - }); + }) } - static async addExtensionHudCombat(html, combatant, token, actions) { + static async addExtensionHudAttaques(html, combatant, token, actions) { const hudData = { combatant, token, actions, commandes: [] }; const divColLeft = $(html).find('div.col.left'); @@ -104,15 +149,6 @@ export class RdDTokenHud { } } - static _initiativeCommand(initCommand, combatantId) { - switch (initCommand) { - case 'inc': return RdDCombatManager.incDecInit(combatantId, 0.01); - case 'dec': return RdDCombatManager.incDecInit(combatantId, -0.01); - case 'autre': return RdDCombatManager.rollInitiativeAction(combatantId, - { name: "Autre action", action: 'autre', system: { initOnly: true, competence: "Autre action" } }); - } - } - /* -------------------------------------------- */ static async addTokenHudExtensions(app, html, tokenId) { console.log(`Adding token HUD extensions for token ${tokenId}`); @@ -132,20 +168,24 @@ export class RdDTokenHud { } /* -------------------------------------------- */ - static async _configureSubMenu(insertMethod, template, hudData, onMenuItem) { + static async _configureSubMenu(callInsertion, template, hudData, onMenuItem) { const hud = $(await renderTemplate(template, hudData)); const list = hud.find('div.rdd-hud-list'); - RdDTokenHud._toggleHudListActive(hud, list); + RdDTokenHud.setupHudToggle(hud, list) - hud.find('img.rdd-hud-togglebutton').click(event => RdDTokenHud._toggleHudListActive(hud, list)); list.find('.rdd-hud-menu').click(onMenuItem); - insertMethod(hud); + callInsertion(hud); } - static _toggleHudListActive(hud, list) { - hud.toggleClass('active'); - HtmlUtility.showControlWhen(list, hud.hasClass('active')); + static setupHudToggle(hud, list) { + function toggleHudList(hud, list) { + hud.toggleClass('active') + HtmlUtility.showControlWhen(list, hud.hasClass('active')) + } + toggleHudList(hud, list) + $(hud).find('img.rdd-hud-togglebutton').click(event => toggleHudList(hud, list)) } + } \ No newline at end of file diff --git a/module/roll/chat-roll-result.mjs b/module/roll/chat-roll-result.mjs index e30f1e72..8ac1c26b 100644 --- a/module/roll/chat-roll-result.mjs +++ b/module/roll/chat-roll-result.mjs @@ -16,10 +16,11 @@ export default class ChatRollResult { static onReady() { foundry.applications.handlebars.loadTemplates({ 'partial-appel-chance': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-appel-chance.hbs', + 'partial-attaque-particuliere': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-attaque-particuliere.hbs', 'partial-encaissement': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-encaissement.hbs', 'partial-recul-choc': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-recul-choc.hbs', 'partial-info-appel-moral': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-info-appel-moral.hbs', - }) + }) } async display(roll) { @@ -38,12 +39,12 @@ export default class ChatRollResult { } prepareDisplay(roll) { - roll.done = roll.done || {} - roll.show = roll.show || {} + roll.done = roll.done ?? {} + roll.show = roll.show ?? {} roll.show.chance = this.isAppelChancePossible(roll) roll.show.encaissement = this.isShowEncaissement(roll) - roll.show.recul = this.getReculChoc(roll) - + roll.show.recul = this.getRecul(roll) + roll.show.particuliere = roll.show.particuliere ?? [] } isAppelChancePossible(roll) { @@ -57,20 +58,36 @@ export default class ChatRollResult { roll.attackerRoll?.dmg.mortalite != 'empoignade' } - getReculChoc(roll, defender = roll.active.actor, attacker = roll.opponent.actor) { - const attaque = roll.attackerRoll - if (attaque && - (roll.rolled.isEchec || !roll.current.defense.isEsquive) && - (attaque.particuliere == 'force' || 'charge' == attaque.tactique?.key)) { - const taille = defender.system.carac.taille.value - const impact = attacker.system.carac.force.value + roll.attackerRoll?.dmg.dmgArme - return { - raison: 'charge' == attaque.tactique?.key ? 'charge' : 'particulière en force', - taille: taille, - impact: impact, - chances: RdDResolutionTable.computeChances(10, taille-impact).norm, - diff: taille - impact - } + + getRecul(roll, defender = roll.active.actor, attacker = roll.opponent.actor) { + switch (roll.type.current) { + case ROLL_TYPE_DEFENSE: + { + const attaque = roll.attackerRoll + if (attaque && + (roll.rolled.isEchec || !roll.current.defense.isEsquive) && + (attaque.particuliere == 'force' || 'charge' == attaque.tactique?.key)) { + const taille = defender.system.carac.taille.value + const impact = attacker.system.carac.force.value + roll.attackerRoll?.dmg.dmgArme + return { + raison: 'charge' == attaque.tactique?.key ? 'charge' : 'particulière en force', + taille: taille, + impact: impact, + chances: RdDResolutionTable.computeChances(10, taille - impact).norm, + diff: taille - impact + } + } + break + } + case ROLL_TYPE_ATTAQUE: + { + const attaque = roll + if (attaque.particuliere == 'force' || 'charge' == attaque.tactique?.key) { + return { + raison: 'charge' == attaque.tactique?.key ? 'charge' : 'particulière en force', + } + } + } } return undefined } @@ -85,6 +102,7 @@ export default class ChatRollResult { $(html).on("click", '.appel-destinee', event => this.onClickAppelDestinee(event)) $(html).on("click", '.encaissement', event => this.onClickEncaissement(event)) $(html).on("click", '.resister-recul', event => this.onClickRecul(event)) + $(html).on("click", '.choix-particuliere', event => this.onClickChoixParticuliere(event)) } @@ -178,4 +196,13 @@ export default class ChatRollResult { await this.updateChatMessage(chatMessage, savedRoll) } + async onClickChoixParticuliere(event) { + const choix = event.currentTarget.attributes['data-particuliere'].value + const chatMessage = ChatUtility.getChatMessage(event) + const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') + savedRoll.particuliere = choix + savedRoll.particulieres = [RDD_CONFIG.particuliere[choix]] + await this.updateChatMessage(chatMessage, savedRoll) + await this.getCombat(savedRoll)?.onAttaqueV2(savedRoll, callbacks) + } } \ No newline at end of file diff --git a/module/roll/roll-basic-parts.mjs b/module/roll/roll-basic-parts.mjs index 3a1c5746..8a6fc14d 100644 --- a/module/roll/roll-basic-parts.mjs +++ b/module/roll/roll-basic-parts.mjs @@ -4,9 +4,10 @@ import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs" import { PART_ATTAQUE } from "./roll-part-attaque.mjs" import { PART_DEFENSE } from "./roll-part-defense.mjs" + export class RollBasicParts { - restore(rollData) { + static restore(rollData) { rollData.ids.sceneId = rollData.ids.sceneId ?? canvas.scene.id rollData.active = RollBasicParts.$getActor(rollData) rollData.opponent = RollBasicParts.$getOpponent(rollData) @@ -15,14 +16,14 @@ export class RollBasicParts { } } - loadSurprises(rollData, type) { + static loadSurprises(rollData, type = rollData.type.current) { if (!rollData.type.passif) { - this.loadSurprise(rollData.active, this.getForceRequiseActiveActor(rollData, type)) - this.loadSurprise(rollData.opponent, 0) + RollBasicParts.loadSurprise(rollData.active, RollBasicParts.getForceRequiseActiveActor(rollData, type)) + RollBasicParts.loadSurprise(rollData.opponent, 0) } } - loadSurprise(who, forceRequise) { + static loadSurprise(who, forceRequise) { if (who?.actor) { foundry.utils.mergeObject(who, StatusEffects.getActorEffetSurprise(who.actor, forceRequise), @@ -30,15 +31,15 @@ export class RollBasicParts { } } - getForceRequiseActiveActor(rollData, type) { + static getForceRequiseActiveActor(rollData, type) { switch (type) { - case ROLL_TYPE_ATTAQUE: return rollData.current[PART_ATTAQUE].attaque.forceRequise + case ROLL_TYPE_ATTAQUE: return rollData.current[PART_ATTAQUE].forceRequise case ROLL_TYPE_DEFENSE: return rollData.current[PART_DEFENSE].forceRequise default: return 0 } } - initFrom(rollData) { + static initFrom(rollData) { return { selected: {}, type: rollData.type, @@ -52,6 +53,16 @@ export class RollBasicParts { } } + static reverseIds(rollData) { + return { + sceneId: rollData.ids.sceneId, + actorId: rollData.ids.opponentId, + actorTokenId: rollData.ids.opponentTokenId, + opponentId: rollData.ids.actorId, + opponentTokenId: rollData.actorTokenId + } + } + static $getActor(rollData) { if (rollData.ids.actorTokenId) { return ActorToken.fromTokenId(rollData.ids.actorTokenId, rollData.ids.sceneId) diff --git a/module/roll/roll-dialog-adapter.mjs b/module/roll/roll-dialog-adapter.mjs index 55beea84..ba3e432f 100644 --- a/module/roll/roll-dialog-adapter.mjs +++ b/module/roll/roll-dialog-adapter.mjs @@ -6,6 +6,10 @@ import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"; import { PART_OEUVRE } from "./roll-part-oeuvre.mjs"; import { RdDItemArme } from "../item/arme.js"; import { RdDBonus } from "../rdd-bonus.js"; +import { ITEM_TYPES, RDD_CONFIG } from "../constants.js"; +import { CARACS } from "../rdd-carac.js"; +import { ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs"; +import { PART_ATTAQUE } from "./roll-part-attaque.mjs"; /* -------------------------------------------- */ export class RollDialogAdapter { @@ -15,21 +19,21 @@ export class RollDialogAdapter { carac: rollData.current.carac.value, diff: rollData.current.totaldiff, bonus: rollData.current.bonus, - sign: rollData.current.sign, showDice: rollData.options.showDice, rollMode: rollData.current.rollmode.key }) const rolled = await RollDialogAdapter.rollChances(rollData, chances) - RollDialogAdapter.adjustRollDataForV1(rollData, rolled, rollTitle) + RollDialogAdapter.setRollDataRolled(rollData, rolled, rollTitle) + RollDialogAdapter.adjustRollDataForV1(rollData) + RollDialogAdapter.adjustAttaqueParticuliere(rollData) return rolled } - static computeChances({ carac, diff, bonus, sign, showDice, rollMode }) { + static computeChances({ carac, diff, bonus, showDice, rollMode }) { const chances = foundry.utils.duplicate(RdDResolutionTable.computeChances(carac, diff)) RdDResolutionTable._updateChancesWithBonus(chances, bonus, diff) - RdDResolutionTable._updateChancesFactor(chances, sign) chances.showDice = showDice chances.rollMode = rollMode return chances @@ -37,7 +41,7 @@ export class RollDialogAdapter { static async rollChances(rollData, chances) { const rolled = await RdDResolutionTable.rollChances(chances, - rollData.current.sign, + rollData.current.sign.diviseur, rollData.current.resultat) rolled.caracValue = rollData.current.carac.value rolled.finalLevel = rollData.current.totaldiff @@ -46,13 +50,20 @@ export class RollDialogAdapter { return rolled } - static adjustRollDataForV1(rollData, rolled, rollTitle) { + static setRollDataRolled(rollData, rolled, rollTitle) { + rollData.rolled = rolled + rollData.choix = rollData.choix ?? {} + rollData.show = rollData.show ?? {} + rollData.show.title = rollTitle + } + + static adjustRollDataForV1(rollData) { + const rolled = rollData.rolled // temporaire pour être homogène roll v1 rollData.alias = rollData.active.actor.getAlias() // pour experience rollData.finalLevel = rollData.current.totaldiff if (rollData.use == undefined) { rollData.use = {} } - if (rollData.show == undefined) { rollData.show = {} } if (rollData.ajustements == undefined) { rollData.ajustements = {} } @@ -75,7 +86,6 @@ export class RollDialogAdapter { if (rollData.current[PART_APPELMORAL]?.checked) { rollData.use.moral = true } - rollData.rolled = rolled if (ReglesOptionnelles.isUsing("afficher-colonnes-reussite")) { rolled.niveauNecessaire = this.findNiveauNecessaire(carac, rolled.roll) rolled.ajustementNecessaire = rolled.niveauNecessaire - diff @@ -88,7 +98,39 @@ export class RollDialogAdapter { descr: aj.diff == undefined ? aj.label : undefined } }) - rollData.show.title = rollTitle + } + + static adjustAttaqueParticuliere(rollData) { + if (rollData.type.current != ROLL_TYPE_ATTAQUE || !rollData.rolled.isPart) { + return + } + + const attaque = rollData.current.attaque; + const choix = [] + const isEmpoignade = attaque.dmg.mortalite == 'empoignade'; + const isCharge = attaque.tactique == 'charge' + /* TODO: cas de créatures faisant des lancers, Glou, Glipzouk */ + const isMeleeDiffNegative = (attaque.comp.type == ITEM_TYPES.competencecreature || rollData.current.carac.key == CARACS.MELEE) + && rollData.current.diff.value < 0 + + // force toujours, sauf empoignade + if (!isEmpoignade) { + choix.push(RDD_CONFIG.particuliere.force) + } + + // finesse seulement en mélée, pour l'empoignade, ou si la difficulté libre est de -1 minimum + if (!isCharge && (isEmpoignade || isMeleeDiffNegative)) { + choix.push(RDD_CONFIG.particuliere.finesse) + } + + // rapidité seulement en mêlée, si l'arme le permet, et si la difficulté libre est de -1 minimum + if (!isCharge && !isEmpoignade && isMeleeDiffNegative && attaque.arme.system.rapide) { + choix.push(RDD_CONFIG.particuliere.rapidite) + } + if (choix.length == 1) { + rollData.particuliere = choix[0].key + } + rollData.particulieres = choix } static mapActionAttaque(attackerRoll) { @@ -99,17 +141,15 @@ export class RollDialogAdapter { return { // correspond à l'attaque de RollPartAttaque (dans rollDta.current.attaque) label: label, - attaque: { - // correspond aux actions d'attaques dans RdDActor.listActionsAttaque - name: label, - // action: 'attaque', - arme: attackerRoll.arme, - comp: attackerRoll.competence, - main: RdDItemArme.getMainAttaque(attackerRoll.competence), - equipe: attackerRoll.arme.system.equipe, - // carac: { key: caracCode, value: caracValue }, - // dommagesArme: dommagesArme, - }, + // correspond aux actions d'attaques dans RdDActor.listActionsAttaque + name: label, + // action: 'attaque', + arme: attackerRoll.arme, + comp: attackerRoll.competence, + main: RdDItemArme.getMainAttaque(attackerRoll.competence), + equipe: attackerRoll.arme.system.equipe, + // carac: { key: caracCode, value: caracValue }, + // dommagesArme: dommagesArme, diff: attackerRoll.diffLibre, particuliere: attackerRoll.particuliere, tactique: RdDBonus.find(attackerRoll.tactique), diff --git a/module/roll/roll-dialog.mjs b/module/roll/roll-dialog.mjs index 6a243ad9..b00c4dae 100644 --- a/module/roll/roll-dialog.mjs +++ b/module/roll/roll-dialog.mjs @@ -37,7 +37,7 @@ import { RollPartAttaque } from "./roll-part-attaque.mjs"; import { RollPartDefense } from "./roll-part-defense.mjs"; import { RollDialogAdapter } from "./roll-dialog-adapter.mjs"; import { ROLLDIALOG_SECTION } from "./roll-part.mjs"; -import { ROLL_TYPE_COMP } from "./roll-constants.mjs"; +import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_COMP } from "./roll-constants.mjs"; import ChatRollResult from "./chat-roll-result.mjs"; import { renderTemplate } from "../constants.js"; @@ -58,8 +58,6 @@ const ALL_ROLL_TYPES = [ // new RollTypeFixedCarac ?? ] -const BASIC_PARTS = new RollBasicParts() - const ROLL_PARTS = [ new RollPartActor(), new RollPartAction(), @@ -257,7 +255,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 rollData.selected = rollData.selected ?? {} rollData.type = rollData.type ?? {} rollData.type.retry = rollData.type.retry ?? false - BASIC_PARTS.restore(rollData) + RollBasicParts.restore(rollData) const potential = ALL_ROLL_TYPES.find(m => m.code == rollData.type.current)?.code const allowed = rollData.type.retry && potential @@ -283,13 +281,14 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 } static saveParts(rollData) { - const target = BASIC_PARTS.initFrom(rollData) + const target = RollBasicParts.initFrom(rollData) ROLL_PARTS.filter(p => p.isActive(rollData)) .forEach(p => p.storeClean(rollData, target)) target.attackerRoll = rollData.attackerRoll target.rolled = rollData.rolled target.result = rollData.result - target.done = target.done ?? {} + target.done = rollData.done ?? {} + target.dmg = rollData.dmg return target } @@ -377,7 +376,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 const types = ALL_ROLL_TYPES.filter(m => m.isAllowed(rollData) && m.visible(rollData)) .map(m => m.toTypeData(rollData)) - BASIC_PARTS.loadSurprises(rollData, this.getSelectedType().code) + RollBasicParts.loadSurprises(rollData, this.getSelectedType().code) rollData.type.label = this.getSelectedType()?.title(rollData) //TOCHECK: set type.label ? const visibleRollParts = RollDialog.getActiveParts(rollData) @@ -423,18 +422,17 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 } async roll() { - // ROLL_PARTS.filter(p => p.isActive(this.rollData)) - // .forEach(p => p.validate(this.rollData)) const roll = RollDialog.saveParts(this.rollData) RollDialog.loadRollData(roll) roll.current.resultat = this.rollData.current[PART_TRICHER]?.resultat ?? -1 - roll.rolled = await this.$rollDice(roll) + roll.choix = {} + roll.rolled = await RollDialogAdapter.rollDice(roll, this.rollTitle(roll)) roll.result = this.getSelectedType(roll).getResult(roll) - console.info('RollDialog.roll:', roll) - await Promise.all(this.rollOptions.callbacks.map(async callback => await callback(roll))) - await this.chatRollResult.display(roll) + console.info('RollDialog.roll:', roll) + await this.chatRollResult.display(roll) + await Promise.all(this.rollOptions.callbacks.map(async callback => await callback(roll))) this.rollOptions.onRollDone(this) } @@ -444,12 +442,9 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 roll.v2 = true } - async defaultCallback(rollData, rolled) { - await rollData.active.actor.appliquerAjoutExperience(rollData) - await rollData.active.actor.appliquerAppelMoral(rollData) + async defaultCallback(roll, rolled) { + await roll.active.actor.appliquerAjoutExperience(roll) + await roll.active.actor.appliquerAppelMoral(roll) } - async $rollDice(rollData) { - return await RollDialogAdapter.rollDice(rollData, this.rollTitle(rollData)) - } } diff --git a/module/roll/roll-part-attaque.mjs b/module/roll/roll-part-attaque.mjs index ca2f41e5..6b2bc4ad 100644 --- a/module/roll/roll-part-attaque.mjs +++ b/module/roll/roll-part-attaque.mjs @@ -1,5 +1,4 @@ import { RdDBonus } from "../rdd-bonus.js" -import { ReglesOptionnelles } from "../settings/regles-optionnelles.js" import { ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs" import { PART_CARAC } from "./roll-part-carac.mjs" import { PART_COMP } from "./roll-part-comp.mjs" @@ -40,12 +39,12 @@ export class RollPartAttaque extends RollPartSelect { choices(refs) { return refs.attaques } static $extractAttaque(attaque, actor) { - return { - key: `${attaque.action}::${attaque.name}`, - label: attaque.name, - attaque: attaque, - tactique: TACTIQUES[0], - } + return foundry.utils.mergeObject({ + key: `${attaque.action}::${attaque.label}`, + tactique: TACTIQUES[0] + }, + attaque + ) } prepareContext(rollData) { @@ -100,8 +99,8 @@ export class RollPartAttaque extends RollPartSelect { if (this.visible(rollData)) { const current = this.getCurrent(rollData) switch (part.code) { - case PART_CARAC: return part.filterCaracs(rollData, [current.attaque.carac.key]) - case PART_COMP: return part.filterComps(rollData, [current.attaque.comp?.name]) + case PART_CARAC: return part.filterCaracs(rollData, [current.carac.key]) + case PART_COMP: return part.filterComps(rollData, [current.comp.name]) } } return undefined diff --git a/module/roll/roll-part-defense.mjs b/module/roll/roll-part-defense.mjs index 82d33c51..e03dcfb0 100644 --- a/module/roll/roll-part-defense.mjs +++ b/module/roll/roll-part-defense.mjs @@ -34,7 +34,7 @@ export class RollPartDefense extends RollPartSelect { .map(it => RollPartDefense.$extractEsquive(it, defenseur)) const parades = defenseur.items.filter(it => it.isParade() && (!refs.isDistance || it.isBouclier())) - .map(it => RollPartDefense.$extractParade(it, attackerRoll?.attaque.arme, defenseur)) + .map(it => RollPartDefense.$extractParade(it, attackerRoll?.arme, defenseur)) refs.defenses = [...esquives, ...parades].filter(it => it != undefined) this.$selectDefense(rollData) @@ -113,17 +113,16 @@ export class RollPartDefense extends RollPartSelect { isArmeDisparate(rollData) { const armeDefense = this.getCurrent(rollData).arme if (armeDefense) { - const armeAttaque = rollData.attackerRoll?.attaque.arme + const armeAttaque = rollData.attackerRoll?.arme return RdDItemArme.defenseArmeParade(armeAttaque, armeDefense) == 'sign' } return false } getDiffDefense(rollData) { - const current = this.getCurrent(rollData) const refs = this.getRefs(rollData) if (refs.isDistance || !rollData.attackerRoll) { - // Déterminer la difficulté de parade + // TODO: Déterminer la difficulté de parade return { diff: 0, type: DIFF.LIBRE } } else { diff --git a/module/roll/roll-type-attaque.mjs b/module/roll/roll-type-attaque.mjs index 0bf07924..f761e9be 100644 --- a/module/roll/roll-type-attaque.mjs +++ b/module/roll/roll-type-attaque.mjs @@ -1,4 +1,5 @@ import { DIFF, ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs" +import { PART_ATTAQUE } from "./roll-part-attaque.mjs" import { RollType } from "./roll-type.mjs" export class RollTypeAttaque extends RollType { @@ -10,4 +11,5 @@ export class RollTypeAttaque extends RollType { onSelect(rollData) { this.setDiffType(rollData, DIFF.ATTAQUE) } + } \ No newline at end of file diff --git a/module/roll/roll-type.mjs b/module/roll/roll-type.mjs index ef7547bc..4b97f57a 100644 --- a/module/roll/roll-type.mjs +++ b/module/roll/roll-type.mjs @@ -11,7 +11,7 @@ export class RollType { get name() { return this.code } get icon() { return `systems/foundryvtt-reve-de-dragon/assets/actions/${this.code}.svg` } get chatResultTemplate() { return `systems/foundryvtt-reve-de-dragon/templates/roll/result/chat-${this.code}.hbs` } - + toTypeData(rollData) { return { code: this.code, name: this.name, icon: this.icon, section: 'type', template: this.template, selected: this.isSelected(rollData) } } @@ -33,11 +33,10 @@ export class RollType { this.typeFromOpponents(rollData), rollData.selected[PART_DIFF].type ] - const type = possibleTypes.find(m => DEFAULT_DIFF_TYPES.includes(m)) ??DIFF.DEFAUT + const type = possibleTypes.find(m => DEFAULT_DIFF_TYPES.includes(m)) ?? DIFF.DEFAUT this.setDiffType(rollData, type) } - typeFromOpponents(rollData) { if (rollData.type.opposed) { if (rollData.type.resistance) { @@ -53,7 +52,7 @@ export class RollType { this.setRollDataType(rollData) } - getResult(rollData){ + getResult(rollData) { return undefined } } diff --git a/templates/actor/combat.hbs b/templates/actor/combat.hbs index 235327dc..563fc29d 100644 --- a/templates/actor/combat.hbs +++ b/templates/actor/combat.hbs @@ -8,16 +8,16 @@ {{#each combat as |action key|}}
  • + data-tooltip="{{action.label}}: niveau {{plusMoins action.comp.system.niveau}}"> {{#if action.arme.img}} {{/if}} - {{action.name}} + {{action.label}} - ({{action.comp.name}}) {{>"systems/foundryvtt-reve-de-dragon/templates/item/icon-arme-broken.hbs" action.arme}} {{plusMoins action.comp.system.niveau}} diff --git a/templates/actor/export-scriptarium/arme.hbs b/templates/actor/export-scriptarium/arme.hbs index 572c9367..6a784d64 100644 --- a/templates/actor/export-scriptarium/arme.hbs +++ b/templates/actor/export-scriptarium/arme.hbs @@ -2,8 +2,8 @@ data-item-id="{{attaque.arme._id}}" data-arme-name="{{attaque.arme.name}}" data-competence-name="{{attaque.comp.name}}"> - {{#if attaque.name}} - {{upperFirst attaque.name}} + {{#if attaque.label}} + {{upperFirst attaque.label}} {{else}}
    {{/if}} diff --git a/templates/chat-demande-defense-v1.hbs b/templates/chat-demande-defense-v1.hbs new file mode 100644 index 00000000..718e86dc --- /dev/null +++ b/templates/chat-demande-defense-v1.hbs @@ -0,0 +1,103 @@ +
    + {{#if (eq surprise 'totale')}} + {{defenderToken.name}} est totalement surpris + {{else if essais.defense}} + {{defenderToken.name}} doit : + {{else}} + {{defenderToken.name}} doit se défendre + {{~#if (eq surprise 'demi')}} avec une significative {{/if}} d'une attaque + {{~#if attaqueParticuliere}} particulière en + {{~#if (eq attaqueParticuliere 'finesse')}} finesse + {{else if (eq attaqueParticuliere 'force')}} force + {{else if (eq attaqueParticuliere 'rapidite')}} rapidité + {{/if~}} + {{/if}} de {{attackerToken.name}} ({{attaqueArme.name}}): + + {{/if}} + +
    + {{#unless (eq surprise 'totale')}} + {{#if essais.defense}} + {{#unless essais.defenseChance}} + {{#if (eq defender.type 'personnage')}} + + Faire appel à la chance + +
    + {{/if}} + {{#if (and (eq defender.type 'personnage') (gt defender.system.compteurs.destinee.value 0))}} + + Utiliser la destinée + +
    + {{/if}} + {{/unless}} + {{else}} + {{#if (settings-get 'rdd-advanced-roll-dialog-v2')}} + + Se défendre + {{#if (or (eq attaqueCategorie 'tir') (eq attaqueCategorie 'lancer'))}} + (difficulté à déterminer) + {{else}} + à {{diffLibre }} + {{/if}} + +
    + {{else}} + {{#each armes as |arme key|}} + + Parer avec {{arme.name}} + {{#if (or (eq ../attaqueCategorie 'tir') (eq ../attaqueCategorie 'lancer'))}} + (difficulté à déterminer) + {{else}}à {{../diffLibre }} + {{/if}} + {{#if (eq arme.typeParade 'sign')}} + ×½ + {{/if}} + {{#if arme.nbUsage}}(Utilisations : {{arme.nbUsage}}){{/if}} + +
    + {{/each}} + {{#if mainsNues}} + + Parer à mains nues à {{diffLibre}}{{#if arme.nbUsage}} (Utilisations : {{arme.nbUsage}}){{/if}} + +
    + {{/if}} + {{#if (ne attaqueCategorie 'tir')}} + {{#each esquives as |esquive key|}} + + {{esquive.name}} + {{#if (or (eq ../attaqueCategorie 'tir') (eq ../attaqueCategorie 'lancer'))}} + (difficulté à déterminer) + {{else}}à {{../diffLibre }} + {{/if}} + {{#if esquive.nbUsage}}(Utilisations : {{esquive.nbUsage}}){{/if}} + +
    + {{/each}} + {{/if}} + {{/if}} + {{/if}} + {{/unless}} + + Encaisser à {{plusMoins dmg.total}} + {{#if (eq dmg.mortalite 'non-mortel')~}} + (non-mortel) ! + {{/if}} + +
    +
    \ No newline at end of file diff --git a/templates/chat-demande-defense.hbs b/templates/chat-demande-defense.hbs index 718e86dc..75d544be 100644 --- a/templates/chat-demande-defense.hbs +++ b/templates/chat-demande-defense.hbs @@ -1,103 +1,59 @@ -
    - {{#if (eq surprise 'totale')}} - {{defenderToken.name}} est totalement surpris - {{else if essais.defense}} - {{defenderToken.name}} doit : - {{else}} - {{defenderToken.name}} doit se défendre - {{~#if (eq surprise 'demi')}} avec une significative {{/if}} d'une attaque - {{~#if attaqueParticuliere}} particulière en - {{~#if (eq attaqueParticuliere 'finesse')}} finesse - {{else if (eq attaqueParticuliere 'force')}} force - {{else if (eq attaqueParticuliere 'rapidite')}} rapidité - {{/if~}} - {{/if}} de {{attackerToken.name}} ({{attaqueArme.name}}): - - {{/if}} - -
    - {{#unless (eq surprise 'totale')}} - {{#if essais.defense}} - {{#unless essais.defenseChance}} - {{#if (eq defender.type 'personnage')}} - - Faire appel à la chance - -
    - {{/if}} - {{#if (and (eq defender.type 'personnage') (gt defender.system.compteurs.destinee.value 0))}} - - Utiliser la destinée - -
    - {{/if}} - {{/unless}} - {{else}} - {{#if (settings-get 'rdd-advanced-roll-dialog-v2')}} - +
    + +
    + +
    +

    Défense de {{opponent.name}}

    +
    + +
    + {{#if (eq opponent.surprise.key 'totale')}} + {{opponent.name}} est totalement surpris + {{else}} + {{opponent.name}} doit se défendre + {{~#if (eq opponent.surprise.key 'demi')}} avec une significative {{/if}} d'une attaque + {{~#if particuliere}} particulière en + {{~#if (eq particuliere 'finesse')}} finesse + {{else if (eq particuliere 'force')}} force + {{else if (eq particuliere 'rapidite')}} rapidité + {{/if~}} + {{/if}} de {{active.name}} ({{current.attaque.label}}): + + {{/if}} +
    + +
    +
    + +
    + +
    +
    \ No newline at end of file diff --git a/templates/chat-infojet.hbs b/templates/chat-infojet.hbs index 696c607d..bc94b4c1 100644 --- a/templates/chat-infojet.hbs +++ b/templates/chat-infojet.hbs @@ -1,13 +1,11 @@ +{{log rolled}}
    {{rolled.caracValue}} à {{plusMoins rolled.finalLevel}} - {{#if (and rolled.factorHtml (gt rolled.factorHtml 1))}} - ×{{{rolled.factorHtml}}} - = {{rolled.score}}% - ×{{{rolled.factorHtml}}} - {{else}} = {{rolled.score}}% + {{#if (and rolled.factorHtml (ne rolled.factorHtml 1))}} + ×{{{rolled.factorHtml}}} {{/if}}
    diff --git a/templates/hud-actor-attaque.hbs b/templates/hud-actor-attaque.hbs index 4f841f16..8d650963 100644 --- a/templates/hud-actor-attaque.hbs +++ b/templates/hud-actor-attaque.hbs @@ -6,8 +6,8 @@
    - + data-tooltip="Attaque: {{action.label}}"> +
    {{/unless}} {{/each}} diff --git a/templates/hud-actor-combat.hbs b/templates/hud-actor-combat.hbs new file mode 100644 index 00000000..e3e921d4 --- /dev/null +++ b/templates/hud-actor-combat.hbs @@ -0,0 +1,34 @@ +{{log this}} +
    + +
    +
    + + +
    + + {{!--
    + +
    --}} + +
    + +
    + +
    +
    diff --git a/templates/hud-actor-init.hbs b/templates/hud-actor-init.hbs index a642e265..e4836c77 100644 --- a/templates/hud-actor-init.hbs +++ b/templates/hud-actor-init.hbs @@ -5,17 +5,17 @@
    - + data-tooltip="Initiative {{action.label}}"> +
    {{/each}} {{#each commandes as |commande key|}}
    - + data-tooltip="{{commande.label}}"> +
    {{/each}}
    diff --git a/templates/roll/result/chat-attaque.hbs b/templates/roll/result/chat-attaque.hbs index e69de29b..9f7fc372 100644 --- a/templates/roll/result/chat-attaque.hbs +++ b/templates/roll/result/chat-attaque.hbs @@ -0,0 +1,75 @@ +
    +
    + + + +
    + +
    + {{active.name}} attaque {{opponent.name}}: {{current.label}} +
    + +
    + {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} +
    {{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} +
    + +
    +
    + {{#if rolled.isSuccess}} + + {{opponent.name}} doit se défendre à {{current.diff.value}}, + {{#if (eq current.dmg.mortalite 'empoignade')}} + ou {{active.name}} marquera un point d'empoignade + {{else if (eq current.dmg.mortalite 'non-mortel')}} + ou encaisser à {{plusMoins current.dmg.total}} (non-mortel) + {{else}} + {{!-- {{~#if (eq current.dmg.mortalite 'mortel')}} --}} + ou encaisser à {{plusMoins current.dmg.total}} + {{!-- {{~#if (eq current.dmg.mortalite 'cauchemar')}} --}} + {{!-- {{else}} + {{plusMoins dmg.total}} (entités de cauchemar) --}} + {{/if}} + + + {{#if show.recul}} + + + Si votre adversaire n'esquive pas cette {{show.recul.raison}}, il devra résister à l'impact ou reculer sous le choc! + + {{/if}} + {{#if (eq particuliere 'rapidite')}} + +
    Votre attaque rapide vous permet une deuxième attaque, ou une défense supplémentaire! +
    + {{/if}} + {{else}} + Votre attaque a échoué! + {{/if}} + {{#if (eq current.tactique 'charge')}} + + + C'est une charge, vos parades auront un -4 et vous ne pourrez pas esquiver! + + {{/if}} + {{#if (and (eq current.tactique 'feinte') rolled.isSuccess)}} + + + Votre feinte peut faire mouche! + + {{/if}} +

    + {{> "systems/foundryvtt-reve-de-dragon/templates/chat-info-appel-au-moral.hbs"}} +

    +
    + +
    + {{> 'partial-attaque-particuliere'}} + {{!-- TODO: maladresses --}} +
    + +
    + {{> 'partial-appel-chance'}} +
    + +
    \ No newline at end of file diff --git a/templates/roll/result/chat-defense.hbs b/templates/roll/result/chat-defense.hbs index b9c078a1..6ff7c97d 100644 --- a/templates/roll/result/chat-defense.hbs +++ b/templates/roll/result/chat-defense.hbs @@ -1,9 +1,8 @@ - -{{log this}}
    +
    @@ -30,20 +29,22 @@ {{!-- {{else}} {{/if}} --}} - {{#if attackerRoll.tactique}} -

    - {{#if (eq attackerRoll.tactique.key 'charge')}} + {{#if (eq attackerRoll.tactique.key 'charge')}} + C'était une charge, les parades de {{opponent.name}} auront un -4 et il ne pourra pas esquiver! - {{else if (eq attackerRoll.tactique.key 'feinte')}} + + {{/if}} + {{#if (eq attackerRoll.tactique.key 'feinte')}} + C'était une feinte! - {{/if}} -

    + {{/if}} {{> 'partial-info-appel-moral'}}
    + {{!-- TODO: maladresses --}} {{> 'partial-recul-choc'}} {{> 'partial-encaissement'}}
    diff --git a/templates/roll/result/chat-oeuvre.hbs b/templates/roll/result/chat-oeuvre.hbs index f1b0b31e..2157d2da 100644 --- a/templates/roll/result/chat-oeuvre.hbs +++ b/templates/roll/result/chat-oeuvre.hbs @@ -1,4 +1,3 @@ -{{log this}}
    diff --git a/templates/roll/result/partial-attaque-particuliere.hbs b/templates/roll/result/partial-attaque-particuliere.hbs new file mode 100644 index 00000000..6a72b10f --- /dev/null +++ b/templates/roll/result/partial-attaque-particuliere.hbs @@ -0,0 +1,16 @@ +{{#if particulieres.length}} + {{#if (eq particulieres.length 1)}} + {{#each particulieres as |part|}} + + Attaque particulière {{part.descr}} + + {{/each}} + {{else}} + {{#each particulieres as |part|}} + + Choisir une particulière {{part.descr}} + + {{/each}} + {{/if}} +{{/if}} \ No newline at end of file diff --git a/templates/roll/roll-part-attaque.hbs b/templates/roll/roll-part-attaque.hbs index a9a90974..28b6e7dd 100644 --- a/templates/roll/roll-part-attaque.hbs +++ b/templates/roll/roll-part-attaque.hbs @@ -4,8 +4,8 @@ - {{#if current.attaque.arme}} - + {{#if current.arme}} + {{/if}} @@ -16,10 +16,10 @@ - {{#if (eq current.attaque.arme.system.mortalite 'empoignade')}} + {{#if (eq current.arme.system.mortalite 'empoignade')}} Empoignade, pas de dommages directs {{else}} - {{#if (and (ne current.attaque.arme.system.mortalite 'non-mortel') (eq current.dmg.penetration 0))}} + {{#if (and (ne current.arme.system.mortalite 'non-mortel') (eq current.dmg.penetration 0))}} {{/if}}
  • {{#each combat as |action key|}}
  • diff --git a/templates/roll/result/chat-meditation.hbs b/templates/roll/result/chat-meditation.hbs index e69de29b..362bc806 100644 --- a/templates/roll/result/chat-meditation.hbs +++ b/templates/roll/result/chat-meditation.hbs @@ -0,0 +1,44 @@ +
    +
    + + +
    +
    + {{active.name}} a médité : {{current.meditation.label}} +
    + +
    + {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} +
    {{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} +
    + +
    +
    + + {{#if rolled.isSuccess}} + + {{active.name}} aperçoit un signe draconique éphémère, qu'il faut aller lire en {{typeTmr-name current.meditation.meditation.system.tmr}}. + + {{else}} + {{active.name}} ne distingue aucun signe Draconique, la meditation n'a pas porté de fruits. + {{/if}} + +
    + {{#if rolled.isEPart}} + + L'échec {{#if rolled.isETotal}}total{{else}}particulier{{/if}} augmente la difficulté de la méditation + {{current.meditation.meditation.name}} de 1 ! + + {{/if}} + + {{#if (regle-optionnelle 'appliquer-fatigue')}} + + + {{active.name}} s'est fatigué{{~#if (actor-isFeminin active.actor)}}e{{/if}} de 2 cases. + + {{/if}} +
    + +
    +
    +
    diff --git a/templates/roll/result/chat-tache.hbs b/templates/roll/result/chat-tache.hbs index e69de29b..cc26cd2e 100644 --- a/templates/roll/result/chat-tache.hbs +++ b/templates/roll/result/chat-tache.hbs @@ -0,0 +1,57 @@ +
    +
    + + +
    +
    + {{active.name}} travaille à sa tâche : {{current.tache.label}} +
    + +
    + {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} +
    {{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} +
    + +
    +
    +

    + {{log 'tache' this }} + {{#if rolled.isSuccess}} + {{active.name}} a obtenu {{rolled.ptTache}} point{{~#unless (eq rolled.ptTache 1)}}s{{/unless}} de tâche, + {{else if (or rolled.isETotal rolled.isEPart)}} + {{active.name}} a perdu {{math-abs rolled.ptTache}} points de tâche, + {{else}} + {{active.name}} n'a pas progressé dans la tâche. + {{/if}} + {{#with current.tache.tache.system as |system|}} + Son avancement est de + + {{system.points_de_tache_courant}} + {{#unless system.cacher_points_de_tache}} sur {{system.points_de_tache}}{{/unless}} + + point{{~#unless (eq system.points_de_tache_courant 1)}}s{{/unless}} de tâche + {{log 'tentatives' (math-sum system.nb_jet_succes system.nb_jet_echec) }} + ({{~#with (math-sum system.nb_jet_succes system.nb_jet_echec) as |tentatives|}} + {{log 'tentatives' tentatives}} + {{~#if (ne tentatives 1)}}{{tentatives}} tentatives{{else}}première tentative{{/if~}} + {{/with~}}). + {{/with}} +

    + + {{#if rolled.isETotal}} + + Son échec total augmente de 1 la difficulté de la tâche! + + {{/if}} + + {{#if (and current.tache.tache.system.fatigue (regle-optionnelle 'appliquer-fatigue'))}} + + + {{active.name}} s'est fatigué{{~#if (actor-isFeminin active.actor)}}e{{/if}} de {{current.tache.tache.system.fatigue}} case{{~#if (gt current.tache.tache.system.fatigue 1)}}s{{/if}}. + + {{/if}} +
    + +
    +
    +
    diff --git a/templates/roll/roll-part-meditation.hbs b/templates/roll/roll-part-meditation.hbs index c673862e..f9be4cbf 100644 --- a/templates/roll/roll-part-meditation.hbs +++ b/templates/roll/roll-part-meditation.hbs @@ -19,14 +19,22 @@ {{current.meditation.system.theme}} Support: {{current.meditation.system.support}} + TMR: {{typeTmr-name current.meditation.system.tmr}} {{#unless current.isTMR}} -   actuelle: {{caseTmr-label rollData.active.actor.system.reve.tmrpos.coord}} {{rollData.active.actor.system.reve.tmrpos.coord}} +  
    + + {{caseTmr-label rollData.active.actor.system.reve.tmrpos.coord}} + {{rollData.active.actor.system.reve.tmrpos.coord}} +
    {{/unless}} +
    Durée: 60 minutes -
    + +
    +