import { SYSTEM } from "../config/system.mjs" import HamalronUtils from "../utils.mjs" export default class HamalronSortilegeCasting { static CHAT_TEMPLATE = "systems/fvtt-hamalron/templates/chat-sortilege.hbs" static DIALOG_TEMPLATE = "systems/fvtt-hamalron/templates/dialog-sortilege-casting.hbs" static getModificateur(categorie, niveau) { const mods = SYSTEM.SORTILEGE_MODIFICATEURS[niveau] return mods?.[categorie] ?? 0 } static getRangMagie(actor) { return actor.system.rangMagie || "initie" } static getEchecMagique(valeurCarteMJ, rang) { const rangs = ["ensorceleur", "initie", "thaumaturge"] const idx = rangs.indexOf(rang) if (idx === -1) return "normal" const paliers = [ { max: 10, resultats: ["normal", "normal", "normal"] }, { max: 13, resultats: ["critique", "normal", "normal"] }, { max: 16, resultats: ["critique", "normal", "normal"] }, { max: 19, resultats: ["critique", "critique", "normal"] }, { max: 23, resultats: ["critique", "critique", "critique"] }, ] for (const palier of paliers) { if (valeurCarteMJ <= palier.max) { return palier.resultats[idx] } } return "critique" } static async prompt(spellItem, actor) { const atouts = actor.items.filter(i => i.type === "tarot" && i.system.type === "atout") const rang = HamalronSortilegeCasting.getRangMagie(actor) const peutUtiliserCoupe = rang === "thaumaturge" const cartesCoupe = peutUtiliserCoupe ? actor.items.filter(i => i.type === "tarot" && i.system.symbole === "coupe" && i.system.type !== "atout") : [] if (atouts.length === 0) { ui.notifications.warn(game.i18n.localize("HAMALRON.Sortilege.noAtout")) return } const niveauData = SYSTEM.NIVEAU_COMPETENCES[spellItem.system.niveauRequis] const niveau = niveauData?.id || spellItem.system.niveauRequis const modificateur = HamalronSortilegeCasting.getModificateur(spellItem.system.categorie, niveau) const categorieLabel = SYSTEM.SORTILEGE_CATEGORIES[spellItem.system.categorie]?.label || spellItem.system.categorie const niveauLabel = niveauData?.name || spellItem.system.niveauRequis const dialogContext = { spell: spellItem, actorName: actor.name, actorImage: actor.img, rang: rang, rangLabel: SYSTEM.RANG_MAGICIEN[rang]?.label || rang, categorieLabel, niveauLabel, modificateur: modificateur >= 0 ? `+${modificateur}` : modificateur, peutUtiliserCoupe, atouts: atouts.map(c => ({ id: c.id, name: c.name, img: c.img, valeur: c.system.valeur, valeurNumerique: HamalronSortilegeCasting.#valeurNumerique(c.system.valeur), })), cartesCoupe: cartesCoupe.map(c => ({ id: c.id, name: c.name, img: c.img, valeur: c.system.valeur, valeurNumerique: HamalronSortilegeCasting.#valeurNumerique(c.system.valeur), })), } const content = await foundry.applications.handlebars.renderTemplate( HamalronSortilegeCasting.DIALOG_TEMPLATE, dialogContext ) const result = await foundry.applications.api.DialogV2.wait({ window: { title: `${game.i18n.localize("HAMALRON.Sortilege.cast")}: ${spellItem.name}` }, classes: ["fvtt-hamalron"], position: { width: 520 }, content, buttons: [ { action: "cancel", label: game.i18n.localize("Cancel"), default: false, }, { action: "cast", label: game.i18n.localize("HAMALRON.Sortilege.cast"), default: true, disabled: true, callback: (event, button, dialog) => { const form = button.form.elements const carteMJ = Number(form["carte-mj"].value) || 0 const selectedAtouts = Array.from(form.querySelectorAll('input[name="atout"]:checked')) .map(el => atouts.find(c => c.id === el.value)) .filter(Boolean) const selectedCoupe = Array.from(form.querySelectorAll('input[name="coupe"]:checked')) .map(el => cartesCoupe.find(c => c.id === el.value)) .filter(Boolean) return { carteMJ, selectedAtouts, selectedCoupe } }, }, ], actions: {}, rejectClose: false, render: (event, dialog) => { const calcTotal = () => { const carteMJ = Number(document.getElementById("carte-mj")?.value || 0) const atoutTotal = Array.from(document.querySelectorAll('input[name="atout"]:checked')) .reduce((sum, el) => sum + (Number(el.dataset.value) || 0), 0) const coupeTotal = Array.from(document.querySelectorAll('input[name="coupe"]:checked')) .reduce((sum, el) => sum + (Number(el.dataset.value) || 0), 0) const total = atoutTotal + coupeTotal const difficulte = carteMJ + modificateur document.getElementById("total-atouts").textContent = String(atoutTotal) document.getElementById("total-coupe").textContent = String(coupeTotal) document.getElementById("total-joueur").textContent = String(total) document.getElementById("difficulte-totale").textContent = String(difficulte) const castBtn = document.querySelector("button[data-action='cast']") const peutLancer = atoutTotal > 0 && carteMJ > 0 castBtn.disabled = !peutLancer } document.querySelectorAll('input[name="atout"], input[name="coupe"], #carte-mj') .forEach(el => el.addEventListener("change", calcTotal)) document.getElementById("draw-card-btn")?.addEventListener("click", async () => { const module = await import("./tarot-deck-manager.mjs") const HamalronTarotDeckManager = module.default if (!HamalronTarotDeckManager._instance) { HamalronTarotDeckManager._instance = new HamalronTarotDeckManager() } const cards = HamalronTarotDeckManager._instance.drawCards(1) if (cards.length > 0) { const valeurData = SYSTEM.TAROT_VALEURS[cards[0].valeur] const value = valeurData?.value || 0 document.getElementById("carte-mj").value = String(value) document.getElementById("carte-mj-nom").textContent = `${cards[0].name} (${value})` calcTotal() } }) calcTotal() }, }) if (!result) return if (result.carteMJ === 0 || result.selectedAtouts.length === 0) return const totalAtouts = result.selectedAtouts.reduce((sum, c) => { return sum + (HamalronSortilegeCasting.#valeurNumerique(c.system.valeur) || 0) }, 0) const totalCoupe = result.selectedCoupe.reduce((sum, c) => { return sum + (HamalronSortilegeCasting.#valeurNumerique(c.system.valeur) || 0) }, 0) const totalJoueur = totalAtouts + totalCoupe const difficulte = result.carteMJ + modificateur const isSuccess = totalJoueur >= difficulte const deckModule = await import("./tarot-deck-manager.mjs") const HamalronTarotDeckManager = deckModule.default if (!HamalronTarotDeckManager._instance) { HamalronTarotDeckManager._instance = new HamalronTarotDeckManager() } const deckManager = HamalronTarotDeckManager._instance if (!isSuccess) { const echecType = HamalronSortilegeCasting.getEchecMagique(result.carteMJ, rang) const nbCartesADefausser = Math.max(1, result.selectedAtouts.length) for (let i = 0; i < nbCartesADefausser && i < result.selectedAtouts.length; i++) { const cardToDiscard = result.selectedAtouts[i] deckManager.addToDiscard({ id: cardToDiscard.id, name: cardToDiscard.name, img: cardToDiscard.img, symbole: cardToDiscard.system.symbole, valeur: cardToDiscard.system.valeur, type: cardToDiscard.system.type, }) const cardItem = actor.items.get(cardToDiscard.id) if (cardItem) { await actor.deleteEmbeddedDocuments("Item", [cardItem.id]) } } const chatDataFail = { cssClass: [SYSTEM.id, "sortilege-roll"].join(" "), isSuccess: false, isNormal: echecType === "normal", isCritique: echecType === "critique", actingCharImg: actor.img, actingCharName: actor.name, spell: spellItem, categorieLabel, niveauLabel, atoutsUtilises: result.selectedAtouts, cartesCoupeUtilisees: result.selectedCoupe, carteMJ: result.carteMJ, modificateur, difficulte, totalJoueur, } const failContent = await foundry.applications.handlebars.renderTemplate( HamalronSortilegeCasting.CHAT_TEMPLATE, chatDataFail ) await ChatMessage.create({ user: game.user.id, speaker: ChatMessage.getSpeaker({ actor }), content: failContent, style: CONST.CHAT_MESSAGE_STYLES.OTHER, }) await deckManager.saveDeckState() deckManager.render() return } for (const card of [...result.selectedAtouts, ...result.selectedCoupe]) { deckManager.addToDiscard({ id: card.id, name: card.name, img: card.img, symbole: card.system.symbole, valeur: card.system.valeur, type: card.system.type, }) const cardItem = actor.items.get(card.id) if (cardItem) { await actor.deleteEmbeddedDocuments("Item", [card.id]) } } const nbCartesAPiocher = result.selectedAtouts.length + result.selectedCoupe.length for (let i = 0; i < nbCartesAPiocher; i++) { if (deckManager.deck.length > 0) { const drawn = deckManager.drawCards(1) if (drawn.length > 0) { const originalItem = await HamalronUtils.findTarotItem(drawn[0]) if (originalItem) { await actor.createEmbeddedDocuments("Item", [originalItem.toObject()]) } } } } const chatDataSuccess = { cssClass: [SYSTEM.id, "sortilege-roll"].join(" "), isSuccess: true, actingCharImg: actor.img, actingCharName: actor.name, spell: spellItem, categorieLabel, niveauLabel, atoutsUtilises: result.selectedAtouts, cartesCoupeUtilisees: result.selectedCoupe, carteMJ: result.carteMJ, modificateur, difficulte, totalJoueur, } const chatContent = await foundry.applications.handlebars.renderTemplate( HamalronSortilegeCasting.CHAT_TEMPLATE, chatDataSuccess ) await ChatMessage.create({ user: game.user.id, speaker: ChatMessage.getSpeaker({ actor }), content: chatContent, style: CONST.CHAT_MESSAGE_STYLES.OTHER, }) await deckManager.saveDeckState() deckManager.render() } static #valeurNumerique(valeur) { const data = SYSTEM.TAROT_VALEURS[valeur] return data?.value ?? (Number.parseInt(valeur) || 0) } }