fix: bouton Épreuve basé sur les cartes de tarot (pas de dés)

Remplace le jet de dés par un vrai dialogue d'épreuve Hamalron :
- Sélection d'une carte dans la main du personnage
- Choix de la difficulté (table standard)
- Calcul réussi/échec basé sur la valeur de la carte
- La carte est défaussée et remplacée depuis le deck
This commit is contained in:
2026-07-10 23:41:22 +02:00
parent e208adfc36
commit 95f6dc6275
2 changed files with 137 additions and 3 deletions
+5 -3
View File
@@ -237,9 +237,11 @@ function addChatTools() {
game.system.api.openActionComplexe() game.system.api.openActionComplexe()
}) })
} }
addBtn("fas fa-dice", "Épreuve", "Lancer une épreuve standard", () => { addBtn("fas fa-cards", "Épreuve", "Lancer une épreuve (choisir une carte)", async () => {
const actor = game.user?.character || game.actors?.find(a => a.type === "personnage") const actor = game.user?.character || game.actors?.find(a => a.type === "personnage" && a.testUserPermission(game.user, "OWNER"))
if (actor) actor.system?.roll?.("stat", { name: "Épreuve", value: 0 }) if (!actor) { ui.notifications.warn("Aucun personnage trouvé"); return }
const { default: HamalronTirageTarot } = await import("./module/documents/tirage-tarot.mjs")
await HamalronTirageTarot.promptEpreuve(actor)
}) })
controls.parentNode.insertBefore(tools, controls) controls.parentNode.insertBefore(tools, controls)
+132
View File
@@ -90,6 +90,138 @@ export default class HamalronTirageTarot extends Roll {
ui.notifications.info(`Le Mat ! Toutes vos cartes ont été défaussées et vous recevez 7 nouvelles cartes. Le deck a été mélangé.`) ui.notifications.info(`Le Mat ! Toutes vos cartes ont été défaussées et vous recevez 7 nouvelles cartes. Le deck a été mélangé.`)
} }
// Carte de symbole par défaut pour les épreuves sans compétence
static async promptEpreuve(actor) {
const tarotCards = actor.items.filter(i => i.type === "tarot")
if (tarotCards.length === 0) {
ui.notifications.warn(game.i18n.localize("HAMALRON.Notifications.noTarotCards"))
return
}
const cardData = tarotCards.map(c => ({
id: c.id,
name: c.name,
img: c.img,
valeur: c.system.valeur,
symbole: c.system.symbole,
type: c.system.type,
valeurNumerique: HamalronTirageTarot.#vNumerique(c.system.valeur),
}))
const content = `
<div class="fvtt-hamalron-roll-dialog">
<fieldset>
<legend>${game.i18n.localize("HAMALRON.Label.selectTarotCard")}</legend>
<div class="tarot-hand">
${cardData.map(c => `
<div class="tarot-card-select" data-card-id="${c.id}" data-card-value="${c.valeurNumerique}">
<img src="${c.img}" alt="${c.name}" />
<span class="card-name">${c.name}</span>
<span class="card-value-display">${c.valeurNumerique}</span>
</div>
`).join("")}
</div>
</fieldset>
<fieldset>
<legend>${game.i18n.localize("HAMALRON.Label.difficulty")}</legend>
<div class="difficulty-row">
<select class="difficulty-select-epreuve">
${Object.entries(SYSTEM.DIFFICULTY_CHOICES).filter(([k]) => k !== "soustension_oppose").map(([k, v]) =>
`<option value="${v.standard}">${v.label} (${v.standard})</option>`
).join("")}
</select>
</div>
</fieldset>
<fieldset class="dialog-result">
<legend>${game.i18n.localize("HAMALRON.Label.total")}</legend>
<div class="total-display">
<span id="card-value-display">+ 0</span>
<span>=</span>
<span id="total-value">0</span>
</div>
<div class="difficulty-info">
<span>${game.i18n.localize("HAMALRON.Label.targetScore")}: <span id="target-score">3</span></span>
</div>
</fieldset>
</div>`
const result = await foundry.applications.api.DialogV2.wait({
window: { title: game.i18n.localize("HAMALRON.Label.titleStandard") },
classes: ["fvtt-hamalron"],
position: { width: 420 },
content,
buttons: [{ action: "roll", label: game.i18n.localize("HAMALRON.Roll.roll"), default: true, callback: (e, btn) => {
const selected = btn.form.querySelector('.tarot-card-select.selected')
if (!selected) return null
return {
cardId: selected.dataset.cardId,
cardValue: Number(selected.dataset.cardValue) || 0,
difficulty: Number(btn.form.querySelector('.difficulty-select-epreuve')?.value || 3),
}
}}, { action: "cancel", label: game.i18n.localize("HAMALRON.Roll.cancel") }],
rejectClose: false,
render: () => {
$(document).off(".epreuve")
$(document).on("click.epreuve", ".tarot-card-select", function () {
$(".tarot-card-select").removeClass("selected")
$(this).addClass("selected")
const val = Number($(this).data("cardValue")) || 0
$("#card-value-display").text(`+ ${val}`)
$("#total-value").text(String(val))
})
$(document).on("change.epreuve", ".difficulty-select-epreuve", function () {
$("#target-score").text($(this).val())
})
},
})
if (!result) return
const cardItem = actor.items.get(result.cardId)
const isSuccess = result.cardValue >= result.difficulty
// Card used: move to discard
const deckModule = await import("../applications/tarot-deck-manager.mjs")
const DM = deckModule.default
if (DM._instance) {
DM._instance.addToDiscard({
id: cardItem.id, name: cardItem.name, img: cardItem.img,
symbole: cardItem.system.symbole, valeur: cardItem.system.valeur,
type: cardItem.system.type,
})
await DM._instance.saveDeckState()
}
if (cardItem) await actor.deleteEmbeddedDocuments("Item", [cardItem.id])
// Draw replacement
if (DM._instance?.deck?.length > 0) {
const drawn = DM._instance.drawCards(1)
if (drawn.length > 0) {
const orig = await HamalronUtils.findTarotItem(drawn[0])
if (orig) await actor.createEmbeddedDocuments("Item", [orig.toObject()])
}
await DM._instance.saveDeckState()
}
ChatMessage.create({
user: game.user.id,
speaker: ChatMessage.getSpeaker({ actor }),
content: `<div class="fvtt-hamalron epreuve-result">
<h3>${game.i18n.localize("HAMALRON.Label.titleStandard")}</h3>
<p><strong>${cardItem?.name}</strong>: ${result.cardValue}</p>
<p>${game.i18n.localize("HAMALRON.Label.difficulty")}: ${result.difficulty}</p>
<p class="${isSuccess ? "result-success" : "result-failure"}">
${isSuccess ? game.i18n.localize("HAMALRON.Label.success") : game.i18n.localize("HAMALRON.Label.failure")}
</p>
</div>`,
style: CONST.CHAT_MESSAGE_STYLES.OTHER,
})
}
static #vNumerique(valeur) {
return SYSTEM.TAROT_VALEURS[valeur]?.value ?? (Number.parseInt(valeur) || 0)
}
static async prompt(options = {}) { static async prompt(options = {}) {
let formula = `3D6 + 0D6KH - 0D6KH + ${options?.rollItem?.value}` let formula = `3D6 + 0D6KH - 0D6KH + ${options?.rollItem?.value}`