Workable system, firt step
This commit is contained in:
+10
-10
@@ -1,14 +1,14 @@
|
||||
export const defaultItemImg = {
|
||||
arme: "systems/fvtt-hamalron/assets/icons/arme.webp",
|
||||
armure: "systems/fvtt-hamalron/assets/icons/armure.webp",
|
||||
competence: "systems/fvtt-hamalron/assets/icons/competence.webp",
|
||||
equipement: "systems/fvtt-hamalron/assets/icons/equipement.webp",
|
||||
faction: "systems/fvtt-hamalron/assets/icons/faction.webp",
|
||||
langue: "systems/fvtt-hamalron/assets/icons/langue.webp",
|
||||
peuple: "systems/fvtt-hamalron/assets/icons/peuple.webp",
|
||||
region: "systems/fvtt-hamalron/assets/icons/region.webp",
|
||||
sortilege: "systems/fvtt-hamalron/assets/icons/sortilege.webp",
|
||||
tarot: "systems/fvtt-hamalron/assets/icons/tarot.webp",
|
||||
arme: "systems/fvtt-hamalron/assets/icons/arme.svg",
|
||||
armure: "systems/fvtt-hamalron/assets/icons/armure.svg",
|
||||
competence: "systems/fvtt-hamalron/assets/icons/competence.svg",
|
||||
equipement: "systems/fvtt-hamalron/assets/icons/equipement.svg",
|
||||
faction: "systems/fvtt-hamalron/assets/icons/faction.svg",
|
||||
langue: "systems/fvtt-hamalron/assets/icons/langue.svg",
|
||||
peuple: "systems/fvtt-hamalron/assets/icons/peuple.svg",
|
||||
region: "systems/fvtt-hamalron/assets/icons/region.svg",
|
||||
sortilege: "systems/fvtt-hamalron/assets/icons/sortilege.svg",
|
||||
tarot: "systems/fvtt-hamalron/assets/icons/tarot.svg",
|
||||
}
|
||||
|
||||
export default class HamalronItem extends Item {
|
||||
|
||||
@@ -8,6 +8,57 @@ export default class HamalronTirageTarot {
|
||||
*/
|
||||
static CHAT_TEMPLATE = "systems/fvtt-hamalron/templates/chat-message.hbs"
|
||||
|
||||
/**
|
||||
* Handle Le Mat special effect when distributed to a player
|
||||
* @param {Actor} actor - The actor who received Le Mat
|
||||
* @param {HamalronTarotDeckManager} deckManager - The deck manager instance
|
||||
*/
|
||||
static async handleLeMatEffect(actor, deckManager) {
|
||||
// 1. Défausser toutes les cartes du joueur
|
||||
const allTarotCards = actor.items.filter(i => i.type === "tarot")
|
||||
if (allTarotCards.length > 0) {
|
||||
const cardIds = allTarotCards.map(c => c.id)
|
||||
await actor.deleteEmbeddedDocuments("Item", cardIds)
|
||||
console.log(`Discarded ${cardIds.length} cards from player`)
|
||||
|
||||
// Ajouter toutes les cartes à la défausse
|
||||
for (const card of allTarotCards) {
|
||||
deckManager.addToDiscard({
|
||||
id: card.id,
|
||||
name: card.name,
|
||||
img: card.img,
|
||||
symbole: card.system.symbole,
|
||||
valeur: card.system.valeur,
|
||||
type: card.system.type,
|
||||
description: card.system.description,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Tirer 7 nouvelles cartes pour le joueur
|
||||
for (let i = 0; i < 7; i++) {
|
||||
if (deckManager.deck.length > 0) {
|
||||
const newCards = deckManager.drawCards(1)
|
||||
if (newCards.length > 0) {
|
||||
const newCard = newCards[0]
|
||||
const originalItem = game.items.get(newCard.id)
|
||||
if (originalItem) {
|
||||
await actor.createEmbeddedDocuments("Item", [originalItem.toObject()])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Regrouper la défausse et le deck, puis mélanger
|
||||
deckManager.deck.push(...deckManager.discard)
|
||||
deckManager.discard = []
|
||||
deckManager.shuffleDeck()
|
||||
|
||||
await deckManager.saveDeckState()
|
||||
deckManager.render()
|
||||
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é.`)
|
||||
}
|
||||
|
||||
static async prompt(options = {}) {
|
||||
let formula = `3D6 + 0D6KH - 0D6KH + ${options?.rollItem?.value}`
|
||||
|
||||
@@ -15,6 +66,34 @@ export default class HamalronTirageTarot {
|
||||
switch (options.rollType) {
|
||||
case "stat":
|
||||
break
|
||||
case "competence":
|
||||
{
|
||||
// Récupérer les cartes de tarot du personnage
|
||||
options.tarotCards = actor.items.filter(i => i.type === "tarot")
|
||||
// Récupérer le modificateur de compétence depuis NIVEAU_COMPETENCES
|
||||
const niveauData = SYSTEM.NIVEAU_COMPETENCES[options.rollItem.system.niveau]
|
||||
options.competenceModifier = niveauData ? niveauData.modificateur : 0
|
||||
|
||||
// Marquer les cartes de succès
|
||||
if (options.tarotCards && actor.system.cartesSucces) {
|
||||
options.tarotCards = options.tarotCards.map(card => {
|
||||
const isSuccessCard = card.system.type !== "atout" && Object.keys(actor.system.cartesSucces).some(symbole => {
|
||||
const successCardData = actor.system.cartesSucces[symbole]
|
||||
return card.system.symbole === symbole &&
|
||||
card.system.valeur === successCardData.value.toString()
|
||||
})
|
||||
// Créer un objet simple avec toutes les propriétés nécessaires
|
||||
return {
|
||||
id: card.id,
|
||||
name: card.name,
|
||||
img: card.img,
|
||||
system: card.system,
|
||||
isSuccessCard: isSuccessCard
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
break
|
||||
case "damage":
|
||||
{
|
||||
let formula = options.rollItem.system.damage
|
||||
@@ -56,6 +135,7 @@ export default class HamalronTirageTarot {
|
||||
let dialogContext = {
|
||||
actorId: options.actorId,
|
||||
actorName: options.actorName,
|
||||
actorImage: options.actorImage,
|
||||
rollType: options.rollType,
|
||||
rollItem: foundry.utils.duplicate(options.rollItem), // Object only, no class
|
||||
weapon: options?.weapon,
|
||||
@@ -69,23 +149,45 @@ export default class HamalronTirageTarot {
|
||||
difficulty: "0",
|
||||
nbAdvantages: "0",
|
||||
nbDisadvantages: "0",
|
||||
tarotCards: options.tarotCards || [],
|
||||
competenceModifier: options.competenceModifier || 0,
|
||||
difficultyChoices: Object.fromEntries(Object.entries(SYSTEM.DIFFICULTY_CHOICES).map(([key, val]) => [key, val.label])),
|
||||
}
|
||||
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-hamalron/templates/roll-dialog.hbs", dialogContext)
|
||||
|
||||
const title = HamalronRoll.createTitle(options.rollType, options.rollTarget)
|
||||
const title = HamalronTirageTarot.createTitle(options.rollType, options.rollTarget)
|
||||
const label = game.i18n.localize("HAMALRON.Roll.roll")
|
||||
const cancelLabel = game.i18n.localize("HAMALRON.Roll.cancel")
|
||||
const rollContext = await foundry.applications.api.DialogV2.wait({
|
||||
window: { title: title },
|
||||
classes: ["fvtt-hamalron"],
|
||||
position: { width: 420 },
|
||||
content,
|
||||
buttons: [
|
||||
{
|
||||
action: "cancel",
|
||||
label: cancelLabel,
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
action: "roll",
|
||||
label: label,
|
||||
default: true,
|
||||
disabled: options.rollType === "competence",
|
||||
callback: (event, button, dialog) => {
|
||||
const output = Array.from(button.form.elements).reduce((obj, input) => {
|
||||
if (input.name) obj[input.name] = input.value
|
||||
return obj
|
||||
}, {})
|
||||
// Ajouter les données de sélection de carte pour les compétences
|
||||
if (options.rollType === "competence") {
|
||||
console.log("DEBUG CALLBACK: options.selectedCardId =", options.selectedCardId, "options.selectedCardValue =", options.selectedCardValue)
|
||||
output.selectedCardId = options.selectedCardId
|
||||
output.selectedCardValue = options.selectedCardValue
|
||||
output.selectedDifficulty = options.selectedDifficulty
|
||||
output.targetScore = options.targetScore
|
||||
console.log("DEBUG CALLBACK: output =", output)
|
||||
}
|
||||
return output
|
||||
},
|
||||
},
|
||||
@@ -96,11 +198,11 @@ export default class HamalronTirageTarot {
|
||||
render: (event, dialog) => {
|
||||
$(".roll-stat-advantages").change(event => {
|
||||
options.nbAdvantages = Number(event.target.value)
|
||||
HamalronRoll.updateFullFormula(options)
|
||||
HamalronTirageTarot.updateFullFormula(options)
|
||||
})
|
||||
$(".roll-stat-disadvantages").change(event => {
|
||||
options.nbDisadvantages = Number(event.target.value)
|
||||
HamalronRoll.updateFullFormula(options)
|
||||
HamalronTirageTarot.updateFullFormula(options)
|
||||
})
|
||||
$(".select-combat-option").change(event => {
|
||||
let field = $(event.target).data("field")
|
||||
@@ -110,14 +212,302 @@ export default class HamalronTirageTarot {
|
||||
} else {
|
||||
options.numericModifier -= modifier
|
||||
}
|
||||
HamalronRoll.updateFullFormula(options)
|
||||
HamalronTirageTarot.updateFullFormula(options)
|
||||
})
|
||||
|
||||
// Gestion de la sélection de carte pour les compétences
|
||||
if (options.rollType === "competence") {
|
||||
let selectedCardId = null
|
||||
options.selectedDifficulty = "soustension_oppose"
|
||||
options.targetScore = null
|
||||
|
||||
// Calculer et afficher les valeurs pour chaque carte
|
||||
const competenceSymbole = options.rollItem.system.carteSymbole
|
||||
$(".tarot-card-select").each(function () {
|
||||
const cardSymbole = $(this).data("card-symbole")
|
||||
const cardValeur = $(this).data("card-valeur")
|
||||
const cardType = $(this).data("card-type")
|
||||
|
||||
const valeurData = SYSTEM.TAROT_VALEURS[cardValeur]
|
||||
const baseValue = valeurData ? valeurData.value : 0
|
||||
|
||||
let calculatedValue = 0
|
||||
if (cardType === "atout") {
|
||||
calculatedValue = baseValue
|
||||
} else if (cardSymbole === competenceSymbole) {
|
||||
calculatedValue = baseValue
|
||||
} else {
|
||||
calculatedValue = Math.ceil(baseValue / 2)
|
||||
}
|
||||
|
||||
$(this).find(".card-values").text(`${baseValue} → ${calculatedValue}`)
|
||||
})
|
||||
|
||||
// Gestion du changement de difficulté
|
||||
$(".difficulty-select").change(function () {
|
||||
const difficultyKey = $(this).val()
|
||||
options.selectedDifficulty = difficultyKey
|
||||
const difficultyData = SYSTEM.DIFFICULTY_CHOICES[difficultyKey]
|
||||
|
||||
if (difficultyData.standard === null) {
|
||||
// Sous tension ou opposé - pas de score cible
|
||||
options.targetScore = null
|
||||
$("#target-score").text("-")
|
||||
} else {
|
||||
options.targetScore = difficultyData.standard
|
||||
$("#target-score").text(options.targetScore)
|
||||
}
|
||||
})
|
||||
|
||||
$(".tarot-card-select").click(function () {
|
||||
// Désélectionner toutes les cartes
|
||||
$(".tarot-card-select").removeClass("selected")
|
||||
// Sélectionner la carte cliquée
|
||||
$(this).addClass("selected")
|
||||
|
||||
selectedCardId = $(this).data("card-id")
|
||||
console.log("DEBUG CLICK: selectedCardId =", selectedCardId)
|
||||
const cardSymbole = $(this).data("card-symbole")
|
||||
const cardValeur = $(this).data("card-valeur")
|
||||
const cardType = $(this).data("card-type")
|
||||
|
||||
// Calculer la valeur de la carte
|
||||
const competenceSymbole = options.rollItem.system.carteSymbole
|
||||
let cardValue = 0
|
||||
|
||||
// Récupérer la valeur numérique de la carte depuis TAROT_VALEURS
|
||||
const valeurData = SYSTEM.TAROT_VALEURS[cardValeur]
|
||||
const baseValue = valeurData ? valeurData.value : 0
|
||||
|
||||
if (cardType === "atout") {
|
||||
// Si c'est un atout, prendre directement la valeur
|
||||
cardValue = baseValue
|
||||
} else if (cardSymbole === competenceSymbole) {
|
||||
// Si le symbole correspond, prendre la valeur complète
|
||||
cardValue = baseValue
|
||||
} else {
|
||||
// Sinon, diviser par 2 arrondi au supérieur
|
||||
cardValue = Math.ceil(baseValue / 2)
|
||||
}
|
||||
|
||||
// Stocker la carte sélectionnée et sa valeur calculée
|
||||
options.selectedCardId = selectedCardId
|
||||
options.selectedCardValue = cardValue
|
||||
console.log("DEBUG CLICK END: options.selectedCardId =", options.selectedCardId, "options.selectedCardValue =", options.selectedCardValue)
|
||||
|
||||
// Mettre à jour l'affichage
|
||||
$("#card-value-display").text(`+ ${cardValue}`)
|
||||
$("#total-value").text(options.competenceModifier + cardValue)
|
||||
|
||||
// Activer le bouton de lancement
|
||||
$("button[data-action='roll']").prop("disabled", false)
|
||||
})
|
||||
|
||||
// Permettre de désélectionner en cliquant à nouveau
|
||||
$(".tarot-card-select").dblclick(function () {
|
||||
$(this).removeClass("selected")
|
||||
options.selectedCardId = null
|
||||
options.selectedCardValue = 0
|
||||
$("#card-value-display").text("+ 0")
|
||||
$("#total-value").text(options.competenceModifier)
|
||||
|
||||
// Désactiver le bouton de lancement
|
||||
$("button[data-action='roll']").prop("disabled", true)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// If the user cancels the dialog, exit
|
||||
if (rollContext === null) return
|
||||
|
||||
// Fusionner les données du dialogue dans options
|
||||
Object.assign(options, rollContext)
|
||||
|
||||
// Gestion spéciale pour les compétences (pas de dés)
|
||||
if (options.rollType === "competence") {
|
||||
const totalValue = options.competenceModifier + (options.selectedCardValue || 0)
|
||||
|
||||
// Récupérer la carte sélectionnée si elle existe
|
||||
let selectedCard = null
|
||||
let cardSymboleMatch = false
|
||||
let isAutomaticSuccess = false
|
||||
|
||||
if (options.selectedCardId) {
|
||||
selectedCard = actor.items.get(options.selectedCardId)
|
||||
if (selectedCard) {
|
||||
cardSymboleMatch = selectedCard.system.symbole === options.rollItem.system.carteSymbole
|
||||
|
||||
// Vérifier si c'est une carte de succès (les atouts ne peuvent jamais être des cartes de succès)
|
||||
if (actor.system.cartesSucces && selectedCard.system.type !== "atout") {
|
||||
isAutomaticSuccess = Object.keys(actor.system.cartesSucces).some(symbole => {
|
||||
const successCardData = actor.system.cartesSucces[symbole]
|
||||
return selectedCard.system.symbole === symbole &&
|
||||
selectedCard.system.valeur === successCardData.value.toString()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Préparer les données pour le chat
|
||||
const difficultyData = SYSTEM.DIFFICULTY_CHOICES[options.selectedDifficulty || "moyenne"]
|
||||
const isSousTensionOppose = options.selectedDifficulty === "soustension_oppose"
|
||||
const isSuccess = isAutomaticSuccess || totalValue > options.targetScore
|
||||
|
||||
// Détecter si la carte est un valet
|
||||
const isValet = selectedCard?.system.valeur === "valet"
|
||||
|
||||
// Détecter si la carte est un cavalier
|
||||
const isCavalier = selectedCard?.system.valeur === "cavalier"
|
||||
|
||||
// Détecter si la carte est une reine
|
||||
const isReine = selectedCard?.system.valeur === "reine"
|
||||
|
||||
// Détecter si la carte est un roi
|
||||
const isRoi = selectedCard?.system.valeur === "roi"
|
||||
|
||||
// Détecter si la carte est un atout
|
||||
const isAtout = selectedCard?.system.type === "atout"
|
||||
|
||||
// Si c'est un cavalier et un échec, transformer en égalité
|
||||
const isEquality = isCavalier && !isSuccess && !isSousTensionOppose
|
||||
|
||||
const chatData = {
|
||||
cssClass: [SYSTEM.id, "competence-roll"].join(" "),
|
||||
actingCharImg: options.actorImage,
|
||||
actingCharName: options.actorName,
|
||||
actorName: options.actorName,
|
||||
competence: options.rollItem,
|
||||
competenceModifier: options.competenceModifier,
|
||||
selectedCard: selectedCard,
|
||||
cardBonus: options.selectedCardValue || 0,
|
||||
cardSymboleMatch: cardSymboleMatch,
|
||||
totalValue: totalValue,
|
||||
difficulty: difficultyData.label,
|
||||
targetScore: options.targetScore,
|
||||
isSuccess: isSuccess,
|
||||
isAutomaticSuccess: isAutomaticSuccess,
|
||||
isSousTensionOppose: isSousTensionOppose,
|
||||
isValet: isValet,
|
||||
isCavalier: isCavalier,
|
||||
isReine: isReine,
|
||||
isRoi: isRoi,
|
||||
isAtout: isAtout,
|
||||
isEquality: isEquality,
|
||||
}
|
||||
|
||||
// Créer le message de chat
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
"systems/fvtt-hamalron/templates/chat-competence.hbs",
|
||||
chatData
|
||||
)
|
||||
|
||||
const messageData = {
|
||||
user: game.user.id,
|
||||
speaker: ChatMessage.getSpeaker({ actor }),
|
||||
content: content,
|
||||
style: CONST.CHAT_MESSAGE_STYLES.OTHER,
|
||||
}
|
||||
|
||||
// Appliquer le mode de visibilité
|
||||
ChatMessage.applyRollMode(messageData, rollContext.visibility)
|
||||
|
||||
await ChatMessage.create(messageData)
|
||||
|
||||
// Gérer la carte utilisée
|
||||
console.log("DEBUG: selectedCard =", selectedCard, "options.selectedCardId =", options.selectedCardId)
|
||||
if (selectedCard) {
|
||||
console.log("Managing used card:", selectedCard.name)
|
||||
// Supprimer la carte de l'acteur
|
||||
const cardItem = actor.items.get(selectedCard.id)
|
||||
if (cardItem) {
|
||||
await actor.deleteEmbeddedDocuments("Item", [selectedCard.id])
|
||||
console.log("Card deleted from actor")
|
||||
}
|
||||
|
||||
// Récupérer le deck manager singleton
|
||||
const module = await import("../applications/tarot-deck-manager.mjs")
|
||||
const HamalronTarotDeckManager = module.default
|
||||
let deckManager = HamalronTarotDeckManager._instance
|
||||
|
||||
// Si le deck manager n'existe pas, le créer
|
||||
if (!deckManager) {
|
||||
console.log("Deck manager not initialized, creating new instance...")
|
||||
deckManager = new HamalronTarotDeckManager()
|
||||
await deckManager.resetDeck()
|
||||
}
|
||||
|
||||
console.log("Deck manager instance:", deckManager)
|
||||
|
||||
if (deckManager) {
|
||||
console.log("Deck manager is available")
|
||||
// Ajouter la carte à la défausse
|
||||
deckManager.addToDiscard({
|
||||
id: selectedCard.id,
|
||||
name: selectedCard.name,
|
||||
img: selectedCard.img,
|
||||
symbole: selectedCard.system.symbole,
|
||||
valeur: selectedCard.system.valeur,
|
||||
type: selectedCard.system.type,
|
||||
description: selectedCard.system.description,
|
||||
})
|
||||
console.log("Card added to discard")
|
||||
|
||||
// Tirer une nouvelle carte automatiquement
|
||||
console.log("Attempting to draw new card. Deck length:", deckManager.deck.length)
|
||||
if (deckManager.deck.length > 0) {
|
||||
const newCards = deckManager.drawCards(1)
|
||||
console.log("Cards drawn:", newCards)
|
||||
if (newCards.length > 0) {
|
||||
const newCard = newCards[0]
|
||||
console.log("New card to add:", newCard)
|
||||
// Trouver l'item tarot dans game.items
|
||||
let originalItem = game.items.get(newCard.id)
|
||||
console.log("Original item found by ID:", originalItem)
|
||||
|
||||
// Si pas trouvé dans game.items, chercher dans tous les items disponibles
|
||||
if (!originalItem) {
|
||||
console.log("Searching for card in game.items by properties...")
|
||||
originalItem = game.items.find(i =>
|
||||
i.type === "tarot" &&
|
||||
i.name === newCard.name &&
|
||||
i.system.symbole === newCard.symbole &&
|
||||
i.system.valeur === newCard.valeur
|
||||
)
|
||||
console.log("Original item found by search:", originalItem)
|
||||
}
|
||||
|
||||
if (originalItem) {
|
||||
// Cas spécial : Le Mat
|
||||
if (newCard.valeur === "lemat") {
|
||||
console.log("Le Mat drawn! Executing special rules...")
|
||||
await HamalronTirageTarot.handleLeMatEffect(actor, deckManager)
|
||||
} else {
|
||||
console.log("Creating embedded document for actor...")
|
||||
await actor.createEmbeddedDocuments("Item", [originalItem.toObject()])
|
||||
console.log("New card added to actor")
|
||||
ui.notifications.info(`${game.i18n.localize("HAMALRON.Notifications.newCardDrawn")}: ${newCard.name}`)
|
||||
}
|
||||
} else {
|
||||
console.warn("Original item not found for card:", newCard)
|
||||
}
|
||||
} else {
|
||||
console.log("No cards were drawn (empty result)")
|
||||
}
|
||||
} else {
|
||||
console.log("Deck is empty, cannot draw new card")
|
||||
}
|
||||
|
||||
deckManager.saveDeckState()
|
||||
deckManager.render()
|
||||
ui.notifications.info(`${game.i18n.localize("HAMALRON.Notifications.cardUsed")}: ${selectedCard.name}`)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
// Code existant pour les autres types de jets
|
||||
let rollData = foundry.utils.mergeObject(foundry.utils.duplicate(options), rollContext)
|
||||
rollData.rollMode = rollContext.visibility
|
||||
rollData.targetScore = 8
|
||||
@@ -203,6 +593,8 @@ export default class HamalronTirageTarot {
|
||||
return `${game.i18n.localize("HAMALRON.Label.titleStat")}`
|
||||
case "weapon":
|
||||
return `${game.i18n.localize("HAMALRON.Label.titleWeapon")}`
|
||||
case "competence":
|
||||
return `${game.i18n.localize("HAMALRON.Label.titleCompetence")}`
|
||||
default:
|
||||
return game.i18n.localize("HAMALRON.Label.titleStandard")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user