fix: migration V14 - rollMode→messageMode, Token HUD, data-message-id

- remplace core.rollMode → core.messageMode (setting V14)
- migre toutes les cles (gmroll→gm, selfroll→self, blindroll→blind)
- corrige le hook renderTokenHUD pour recuperer le tokenId via app.document
- ajoute un bouton combat personnalise si absent du HUD V14
- corrige le toggle combat : isCombat manquant et guard si hors combat
- chat-utility : data-document-id→data-message-id pour les messages V14
- rdd-utility : idem pour findChatMessage/getChatMessageId
- roll-part-possession : getBestDraconic peut retourner undefined
- distance.mjs : Token→foundry.canvas.placeables.Token
This commit is contained in:
fabres
2026-07-22 00:29:56 +02:00
parent a5843888c0
commit 1c288b654a
18 changed files with 72 additions and 62 deletions
+4 -4
View File
@@ -1646,10 +1646,10 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async ajoutExperience(rollData, hideChatMessage = 'show') {
const rollMode = rollData.current?.rollmode?.key ?? game.settings.get("core", "rollMode")
const rollMode = rollData.current?.rollmode?.key ?? game.settings.get("core", "messageMode")
if (!rollData.rolled.isPart ||
rollData.finalLevel >= 0 ||
rollMode == 'selfroll' ||
rollMode == 'self' ||
!Misc.hasConnectedGM()) {
return
}
@@ -1675,7 +1675,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async appliquerAppelMoral(rollData) {
if (!rollData.use.moral || game.settings.get("core", "rollMode") == 'selfroll') {
if (!rollData.use.moral || game.settings.get("core", "messageMode") == 'self') {
return
}
if (rollData.rolled.isEchec ||
@@ -3057,7 +3057,7 @@ export class RdDActor extends RdDBaseActorSang {
incarnation.name = 'Réincarnation de ' + incarnation.name
incarnation.system = {
carac: foundry.utils.deepClone(this.system.carac),
heure: RdDTimestamp.defHeure(await RdDDice.rollHeure({ rollMode: "selfroll", showDice: SHOW_DICE })).key,
heure: RdDTimestamp.defHeure(await RdDDice.rollHeure({ rollMode: "self", showDice: SHOW_DICE })).key,
age: 18,
biographie: '',
notes: '',
+1 -1
View File
@@ -362,7 +362,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
selectedCarac: carac,
competence: competence,
diffLibre: diff ?? 0,
current: { rollmode: { key: game.settings.get("core", "rollMode") } },
current: { rollmode: { key: game.settings.get("core", "messageMode") } },
show: { title: options?.title ?? '' }
}
RollDataAjustements.calcul(rollData, this);
@@ -38,7 +38,7 @@ async function randomPoidsKg(taille) {
}
async function randomHeure() {
return RdDTimestamp.defHeure(await RdDDice.rollHeure({ rollMode: "selfroll", showDice: SHOW_DICE })).key
return RdDTimestamp.defHeure(await RdDDice.rollHeure({ rollMode: "self", showDice: SHOW_DICE })).key
}
const CONTROL_UNKNOWN = { name: 'unknown', path: '', getter: (act) => { undefined }, random: async act => undefined }
+11 -10
View File
@@ -93,9 +93,9 @@ export class ChatUtility {
/* -------------------------------------------- */
static adaptVisibility( messageData, options = { actor: undefined, rollMode: undefined }) {
foundry.utils.mergeObject(options, { rollMode: game.settings.get("core", "rollMode") }, { overwrite: false });
foundry.utils.mergeObject(options, { rollMode: game.settings.get("core", "messageMode") }, { overwrite: false });
switch (options.rollMode) {
case "blindroll": // GM only
case "blind": // GM only
if (!game.user.isGM) {
ChatUtility.blindMessageToGM(messageData)
messageData.whisper = [game.user]
@@ -105,10 +105,10 @@ export class ChatUtility {
messageData.whisper = ChatUtility.getGMs()
}
break;
case "gmroll":
case "gm":
messageData.whisper = options.actor ? ChatUtility.getOwners(options.actor) : ChatUtility.getUserAndGMs()
break;
case "selfroll":
case "self":
messageData.whisper = [game.user]
break
}
@@ -158,21 +158,21 @@ export class ChatUtility {
return game.users.filter(user => user.isGM)
}
static applyRollMode(chatMessageData = {}, rollMode = game.settings.get("core", "rollMode")) {
static applyRollMode(chatMessageData = {}, rollMode = game.settings.get("core", "messageMode")) {
switch (rollMode) {
case "blindroll":
case "blind":
chatMessageData.blind = true
chatMessageData.whisper = ChatUtility.getGMs()
break
case "gmroll":
case "gm":
chatMessageData.whisper = ChatUtility.getGMs()
chatMessageData.blind = false
break
case "roll":
case "public":
chatMessageData.whisper = ChatUtility.getUsers(user => user.active)
chatMessageData.blind = false
break
case "selfroll":
case "self":
chatMessageData.whisper = [game.user]
chatMessageData.blind = false
break
@@ -211,7 +211,8 @@ export class ChatUtility {
}
static getChatMessage(event) {
const chatMessageId = $(event.currentTarget).closest('.chat-message').attr('data-document-id');
const chatMessageEl = $(event.currentTarget).closest('.chat-message');
const chatMessageId = chatMessageEl.attr('data-document-id') ?? chatMessageEl.attr('data-message-id');
return game.messages.get(chatMessageId);
}
+1 -1
View File
@@ -116,7 +116,7 @@ export class Distance {
}
static $isToken(token) {
return token instanceof Token || token instanceof TokenDocument
return token instanceof foundry.canvas.placeables.Token || token instanceof TokenDocument
}
}
+1 -1
View File
@@ -26,7 +26,7 @@ export class RdDItemMaladie extends RdDItem {
whisper: ChatUtility.getOwners(mal.actor),
content: `${mal.actor.name} souffre ${souffrance} (${Misc.typeName('Item', mal.type)}): vérifiez que les effets ne se sont pas aggravés !`
})
mal.postItemToChat('gmroll')
mal.postItemToChat('gm')
await RdDItemMaladie.prolongerPeriode(mal, oldTimestamp, newTimestamp)
}
}
+2 -2
View File
@@ -201,8 +201,8 @@ export class Misc {
}
static isRollModeHiddenToPlayer() {
const mode = game.settings.get("core", "rollMode");
return mode === "blindroll" || mode === "gmroll" || mode === "selfroll";
const mode = game.settings.get("core", "messageMode");
return mode === "blind" || mode === "gm" || mode === "self";
}
static getActiveUser(id) {
+1 -1
View File
@@ -150,7 +150,7 @@ export class RdDCombatManager extends Combat {
}])
// Send a chat message
let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode");
let rollMode = messageOptions.rollMode || game.settings.get("core", "messageMode");
let messageData = foundry.utils.mergeObject({
speaker: {
scene: canvas?.scene?.id,
+1 -1
View File
@@ -107,7 +107,7 @@ export class RdDResolutionTable {
this._updateChancesWithBonus(chances, rollData.bonus, finalLevel);
this._updateChancesFactor(chances, rollData.diviseurSignificative);
chances.showDice = rollData.showDice;
chances.rollMode = rollData.current?.rollmode?.key ?? game.settings.get("core", "rollMode")
chances.rollMode = rollData.current?.rollmode?.key ?? game.settings.get("core", "messageMode")
let rolled = await this.rollChances(chances, rollData.diviseurSignificative, rollData.forceDiceResult);
rolled.caracValue = caracValue;
+1 -1
View File
@@ -6,7 +6,7 @@ export class RdDRollResult {
static async displayRollData(rollData, actor = undefined, template = 'chat-resultat-general.hbs') {
return await ChatMessage.create(ChatUtility.adaptVisibility(
{ content: await RdDRollResult.buildRollDataHtml(rollData, template) },
{ actor: actor, rollMode: rollData.current?.rollmode?.key ?? game.settings.get("core", "rollMode") }
{ actor: actor, rollMode: rollData.current?.rollmode?.key ?? game.settings.get("core", "messageMode") }
))
}
+10 -10
View File
@@ -5,7 +5,7 @@ export class RdDRollTables {
/* -------------------------------------------- */
static async genericGetTableResult(tableName, toChat) {
let table = RdDRollTables.getWorldTable(tableName) ?? (await RdDRollTables.getSystemTable(tableName));
const draw = await table.draw({ displayChat: toChat, rollMode: "gmroll" });
const draw = await table.draw({ displayChat: toChat, rollMode: "gm" });
return draw.results.length > 0 ? draw.results[0] : undefined;
}
@@ -34,7 +34,7 @@ export class RdDRollTables {
}
/* -------------------------------------------- */
static async getCompetence(toChat = false, rollMode = "gmroll") {
static async getCompetence(toChat = false, rollMode = "gm") {
if (toChat == 'liste') {
return await RdDRollTables.listOrRoll('competences', 'Item', ['competence'], toChat, rollMode, it => 1);
}
@@ -44,44 +44,44 @@ export class RdDRollTables {
}
/* -------------------------------------------- */
static async getSouffle(toChat = false, rollMode = "gmroll") {
static async getSouffle(toChat = false, rollMode = "gm") {
return await RdDRollTables.listOrRoll('souffles-de-dragon', 'Item', ['souffle'], toChat, rollMode);
}
/* -------------------------------------------- */
static async getQueue(toChat = false, rollMode = "gmroll") {
static async getQueue(toChat = false, rollMode = "gm") {
return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', ['queue'], toChat, rollMode);
}
static async getDesirLancinant(toChat = false, rollMode = "gmroll") {
static async getDesirLancinant(toChat = false, rollMode = "gm") {
return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', ['queue'], toChat, rollMode,
it => it.system.frequence,
it => it.system.categorie == 'lancinant');
}
static async getIdeeFixe(toChat = false, rollMode = "gmroll") {
static async getIdeeFixe(toChat = false, rollMode = "gm") {
return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', ['queue'], toChat, rollMode,
it => it.system.frequence,
it => it.system.categorie == 'ideefixe');
}
/* -------------------------------------------- */
static async getTeteHR(toChat = false, rollMode = "gmroll") {
static async getTeteHR(toChat = false, rollMode = "gm") {
return await RdDRollTables.listOrRoll('tetes-de-dragon-pour-haut-revants', 'Item', ['tete'], toChat, rollMode);
}
/* -------------------------------------------- */
static async getTete(toChat = false, rollMode = "gmroll") {
static async getTete(toChat = false, rollMode = "gm") {
return await RdDRollTables.listOrRoll('tetes-de-dragon-pour-tous-personnages', 'Item', ['tete'], toChat, rollMode);
}
/* -------------------------------------------- */
static async getOmbre(toChat = false, rollMode = "gmroll") {
static async getOmbre(toChat = false, rollMode = "gm") {
return await RdDRollTables.listOrRoll('ombres-de-thanatos', 'Item', ['ombre'], toChat, rollMode);
}
/* -------------------------------------------- */
static async getTarot(toChat = true, rollMode = "gmroll") {
static async getTarot(toChat = true, rollMode = "gm") {
return await RdDRollTables.listOrRoll('tarot-draconique', 'Item', ['tarot'], toChat, rollMode);
}
+23 -16
View File
@@ -11,7 +11,7 @@ export class RdDTokenHud {
static init() {
// Integration du TokenHUD
Hooks.on('renderTokenHUD', (app, html, token) => { RdDTokenHud.addTokenHudExtensions(app, html, token.id) });
Hooks.on('renderTokenHUD', (app, html) => { RdDTokenHud.addTokenHudExtensions(app, html, app.document?.id) });
}
/* -------------------------------------------- */
@@ -24,14 +24,14 @@ export class RdDTokenHud {
static async addExtensionHud(app, html, tokenId, isCombat) {
let token = canvas?.tokens?.get(tokenId);
if (!token) return;
let actor = token.actor;
let actor = token?.actor ?? app.actor;
app.hasExtension = true;
// soins
await RdDTokenHud.addExtensionHudSoins(html, actor);
if (isCombat) {
const combatant = game.combat.combatants.find(c => c.tokenId == tokenId)
const combatant = game.combat?.combatants?.find(c => c.tokenId == tokenId)
if (!combatant) return;
const actor = RdDCombatManager.getActorCombatant(combatant, { warning: false })
if (actor) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
@@ -165,19 +165,26 @@ export class RdDTokenHud {
/* -------------------------------------------- */
static async addTokenHudExtensions(app, html, tokenId) {
console.log(`Adding token HUD extensions for token ${tokenId}`);
const controlIconCombat = $(html).find('.control-icon[data-action=combat]');
if (controlIconCombat.length > 0) {
controlIconCombat.click(event => {
if (event.currentTarget.className.includes('active')) {
RdDTokenHud.removeExtensionHud(app, html, tokenId);
} else {
setTimeout(() => RdDTokenHud.addExtensionHud(app, html, tokenId), 200);
}
});
const isCombat = controlIconCombat[0].className.includes('active');
RdDTokenHud.addExtensionHud(app, html, tokenId, isCombat);
let controlIconCombat = $(html).find('.control-icon[data-action=combat]');
if (!controlIconCombat.length) {
const colLeft = $(html).find('div.col.left');
if (!colLeft.length) return;
controlIconCombat = $(`<button type="button" class="control-icon" data-action="combat" data-tooltip="Actions de combat" aria-label="Actions de combat"><i class="fa-solid fa-crosshairs" inert=""></i></button>`);
colLeft.append(controlIconCombat);
}
controlIconCombat.click(event => {
const btn = event.currentTarget;
if (btn.className.includes('active')) {
btn.classList.remove('active');
RdDTokenHud.removeExtensionHud(app, html, tokenId);
} else {
btn.classList.add('active');
setTimeout(() => RdDTokenHud.addExtensionHud(app, html, tokenId, true), 200);
}
});
const isCombat = controlIconCombat[0].className.includes('active');
RdDTokenHud.addExtensionHud(app, html, tokenId, isCombat);
}
/* -------------------------------------------- */
+5 -3
View File
@@ -892,11 +892,13 @@ export class RdDUtility {
}
static getChatMessageId(node) {
return node?.attributes.getNamedItem('data-document-id')?.value;
return node?.attributes.getNamedItem('data-document-id')?.value
?? node?.attributes.getNamedItem('data-message-id')?.value;
}
static findChatMessage(current) {
return RdDUtility.findNodeMatching(current, it => it.classList.contains('chat-message') && it.attributes.getNamedItem('data-document-id'));
return RdDUtility.findNodeMatching(current, it => it.classList.contains('chat-message')
&& (it.attributes.getNamedItem('data-document-id') || it.attributes.getNamedItem('data-message-id')));
}
static findNodeMatching(current, predicate) {
@@ -1000,7 +1002,7 @@ export class RdDUtility {
static chatDataSetup(content, modeOverride, isRoll = false, forceWhisper) {
let chatData = {
user: game.user.id,
rollMode: modeOverride || game.settings.get("core", "rollMode"),
rollMode: modeOverride || game.settings.get("core", "messageMode"),
content: content
}
ChatUtility.applyRollMode(chatData)
+1 -1
View File
@@ -314,7 +314,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
ALL_ROLL_TYPES.find(m => m.code == rollType).setRollDataType(rollData)
rollData.refs = foundry.utils.mergeObject(rollData.refs ?? {}, Object.fromEntries(allowedRollParts.map(p => [p.code, {}])));
rollData.options = rollData.options ?? { rollMode: game.settings.get("core", "rollMode") }
rollData.options = rollData.options ?? { rollMode: game.settings.get("core", "messageMode") }
allowedRollParts.forEach(p => RollDialog.$initializeRollPart(rollData, p.code))
allowedRollParts
+1 -1
View File
@@ -31,7 +31,7 @@ export class RollPartPossession extends RollPartSelect {
$getActorConjurations(rollData) {
const competences = rollData.active.actor.getBestDraconic({possession: true})
return competences.map(RollPartPossession.extractPossession)
return (competences ? [competences] : []).map(RollPartPossession.extractPossession)
}
static extractPossession(comp) {
+3 -3
View File
@@ -13,7 +13,7 @@ export class RollPartRollMode extends RollPart {
}
restore(rollData) {
this.setCurrent(rollData, { key: this.getSaved(rollData)?.key ?? game.settings.get("core", "rollMode") })
this.setCurrent(rollData, { key: this.getSaved(rollData)?.key ?? game.settings.get("core", "messageMode") })
}
store(rollData, targetData) {
@@ -37,8 +37,8 @@ export class RollPartRollMode extends RollPart {
}
async onUpdateSetting(rollDialog, setting, update, options, id) {
if (setting == 'core.rollMode') {
this.setCurrent(rollDialog.rollData, { key: game.settings.get("core", "rollMode") })
if (setting == 'core.messageMode') {
this.setCurrent(rollDialog.rollData, { key: game.settings.get("core", "messageMode") })
rollDialog.render()
}
}
+3 -3
View File
@@ -236,7 +236,7 @@ export class RdDCalendrier extends HandlebarsApplicationMixin(foundry.applicatio
/* -------------------------------------------- */
async ajouterNombreAstral(indexDate) {
const nombreAstral = await RdDDice.rollHeure( { showDice: HIDE_DICE, rollMode: "selfroll" });
const nombreAstral = await RdDDice.rollHeure( { showDice: HIDE_DICE, rollMode: "self" });
return {
nombreAstral: nombreAstral,
lectures: [],
@@ -348,7 +348,7 @@ export class RdDCalendrier extends HandlebarsApplicationMixin(foundry.applicatio
caracValue: request.carac_vue,
finalLevel: niveau,
showDice: HIDE_DICE,
rollMode: "blindroll"
rollMode: "blind"
};
await RdDResolutionTable.rollData(rollData);
request.rolled = rollData.rolled;
@@ -364,7 +364,7 @@ export class RdDCalendrier extends HandlebarsApplicationMixin(foundry.applicatio
}
else {
request.nbAstral = await RdDDice.rollTotal("1dhr" + request.nbAstral, {
rollMode: "selfroll", showDice: HIDE_DICE
rollMode: "self", showDice: HIDE_DICE
});
}
await this.addNbAstralJoueur(actor, request.date, request.nbAstral, request.isValid)
+2 -2
View File
@@ -38,7 +38,7 @@ export class TMRRencontres {
const frequence = it => it.system.frequence[tmrType];
const row = await this.table.getRandom(frequence, filtreMauvaise, forcedRoll);
if (row) {
await CompendiumTableHelpers.tableRowToChatMessage(row, 'Item', { showSource: false, rollMode: "gmroll" });
await CompendiumTableHelpers.tableRowToChatMessage(row, 'Item', { showSource: false, rollMode: "gm" });
}
return row?.document;
@@ -118,6 +118,6 @@ export class TMRRencontres {
sound: CONFIG.sounds.dice,
content: flavorContent
};
ChatMessage.create(messageData, { rollMode: "gmroll" });
ChatMessage.create(messageData, { rollMode: "gm" });
}
}