Latest updates

This commit is contained in:
2026-07-10 16:58:33 +02:00
parent 8a27cef9a4
commit cd2e07ed97
22 changed files with 363 additions and 181 deletions
+168 -12
View File
@@ -30,6 +30,9 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
collectHands: HamalronTarotDeckManager.#onCollectHands,
distributeCards: HamalronTarotDeckManager.#onDistributeCards,
drawTension: HamalronTarotDeckManager.#onDrawTension,
drawThreeTrumps: HamalronTarotDeckManager.#onDrawThreeTrumps,
drawEightNumbered: HamalronTarotDeckManager.#onDrawEightNumbered,
drawOneTrump: HamalronTarotDeckManager.#onDrawOneTrump,
},
}
@@ -316,7 +319,8 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
}
/**
* Distribute 8 cards to all connected players
* Distribute 8 cards to all connected players (starting hand)
* Excludes the Mat from distribution, then returns it to the deck and reshuffles
* @param {Event} event
* @param {HTMLElement} target
*/
@@ -337,6 +341,7 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
let distributedCount = 0
let playersCount = 0
let matCard = null
// Récupérer tous les utilisateurs connectés (sauf le GM)
const connectedPlayers = game.users.filter(u => u.active && !u.isGM)
@@ -349,10 +354,22 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
)
if (playerCharacter) {
// Tirer 8 cartes pour ce personnage
// Tirer 8 cartes pour ce personnage (en ignorant le Mat)
const cardsToDistribute = []
for (let i = 0; i < 8 && this.deck.length > 0; i++) {
let attempts = 0
const maxAttempts = this.deck.length + 10 // Safety limit
while (cardsToDistribute.length < 8 && this.deck.length > 0 && attempts < maxAttempts) {
const card = this.deck.shift()
attempts++
// Si c'est le Mat, le mettre de côté
if (card.valeur === "lemat") {
matCard = card
console.log("Le Mat trouvé et mis de côté pour être remis dans le deck après distribution")
continue
}
cardsToDistribute.push(card)
}
@@ -362,14 +379,6 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
if (originalItem) {
await playerCharacter.createEmbeddedDocuments("Item", [originalItem.toObject()])
distributedCount++
// Cas spécial : Le Mat
if (card.valeur === "lemat") {
console.log(`Le Mat distributed to ${playerCharacter.name}! Executing special rules...`)
// Import de TirageTarot pour accéder à la fonction helper
const { default: HamalronTirageTarot } = await import("../documents/tirage-tarot.mjs")
await HamalronTirageTarot.handleLeMatEffect(playerCharacter, this)
}
}
}
@@ -377,6 +386,16 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
}
}
// Remettre le Mat dans le deck si il a été trouvé
if (matCard) {
this.deck.push(matCard)
console.log("Le Mat a été remis dans le deck")
}
// Remélanger le deck restant
this.shuffleDeck()
console.log("Le deck restant a été remélangé")
this.saveDeckState()
ui.notifications.info(
@@ -389,6 +408,105 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
this.render()
}
/**
* Draw 3 trumps (atouts only)
* Cards are returned to deck and reshuffled after draw
* @param {Event} event
* @param {HTMLElement} target
*/
static async #onDrawThreeTrumps(event, target) {
const trumpCards = this.deck.filter(card => card.type === "atout")
if (trumpCards.length < 3) {
ui.notifications.warn(game.i18n.localize("HAMALRON.TarotDeck.NotEnoughTrumps"))
return
}
// Tirer 3 atouts au hasard
const drawnCards = []
const availableTrumps = [...trumpCards]
for (let i = 0; i < 3; i++) {
const randomIndex = Math.floor(Math.random() * availableTrumps.length)
const card = availableTrumps.splice(randomIndex, 1)[0]
drawnCards.push(card)
}
// Envoyer au chat
await this.sendCardsToChat(drawnCards)
// Remélanger le deck (les cartes restent dedans)
this.shuffleDeck()
this.saveDeckState()
this.render()
ui.notifications.info(game.i18n.localize("HAMALRON.TarotDeck.ThreeTrumpsDrawn"))
}
/**
* Draw 8 numbered cards (cards 1-10 from the 4 symbols)
* Cards are returned to deck and reshuffled after draw
* @param {Event} event
* @param {HTMLElement} target
*/
static async #onDrawEightNumbered(event, target) {
const numberedCards = this.deck.filter(card => card.type === "numéro")
if (numberedCards.length < 8) {
ui.notifications.warn(game.i18n.localize("HAMALRON.TarotDeck.NotEnoughNumbered"))
return
}
// Tirer 8 cartes numérotées au hasard
const drawnCards = []
const availableNumbered = [...numberedCards]
for (let i = 0; i < 8; i++) {
const randomIndex = Math.floor(Math.random() * availableNumbered.length)
const card = availableNumbered.splice(randomIndex, 1)[0]
drawnCards.push(card)
}
// Envoyer un résumé au chat
await this.sendNumberedCardsSummaryToChat(drawnCards)
// Remélanger le deck (les cartes restent dedans)
this.shuffleDeck()
this.saveDeckState()
this.render()
ui.notifications.info(game.i18n.localize("HAMALRON.TarotDeck.EightNumberedDrawn"))
}
/**
* Draw 1 trump (atout only)
* Card is returned to deck and reshuffled after draw
* @param {Event} event
* @param {HTMLElement} target
*/
static async #onDrawOneTrump(event, target) {
const trumpCards = this.deck.filter(card => card.type === "atout")
if (trumpCards.length === 0) {
ui.notifications.warn(game.i18n.localize("HAMALRON.TarotDeck.NoTrumpsAvailable"))
return
}
// Tirer 1 atout au hasard
const randomIndex = Math.floor(Math.random() * trumpCards.length)
const card = trumpCards[randomIndex]
// Envoyer au chat
await this.sendCardsToChat([card])
// Remélanger le deck (la carte reste dedans)
this.shuffleDeck()
this.saveDeckState()
this.render()
ui.notifications.info(game.i18n.localize("HAMALRON.TarotDeck.OneTrumpDrawn"))
}
/**
* Shuffle discard pile back into deck
* @param {Event} event
@@ -437,7 +555,7 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
const content = `
<div class="form-group">
<label>{{localize "HAMALRON.Label.difficulty"}}</label>
<label>${game.i18n.localize("HAMALRON.Label.difficulty")}</label>
<select id="tension-difficulty" style="width: 100%;">
${selectOptions}
</select>
@@ -524,6 +642,44 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
})
}
/**
* Send numbered cards summary to chat
* @param {Array} cards - Array of numbered cards
*/
async sendNumberedCardsSummaryToChat(cards) {
const speaker = ChatMessage.getSpeaker({ alias: "Maître du Jeu" })
// Créer la liste des cartes
const cardsList = cards.map(card => {
const symboleLabel = game.i18n.localize(`HAMALRON.Tarot.FIELDS.symbole.${card.symbole}`)
const valeurLabel = game.i18n.localize(`HAMALRON.Tarot.FIELDS.valeur.${card.valeur}`)
return `
<div class="tarot-card-summary-item">
<img src="${card.img}" alt="${card.name}" title="${card.name}" />
<span class="card-name">${valeurLabel} de ${symboleLabel}</span>
</div>
`
}).join('')
const content = `
<div class="fvtt-hamalron chat-tarot-summary">
<h3 class="tarot-summary-title">
<i class="fas fa-hashtag"></i>
${game.i18n.localize("HAMALRON.TarotDeck.EightNumberedCardsDrawn")}
</h3>
<div class="tarot-cards-grid">
${cardsList}
</div>
</div>
`
await ChatMessage.create({
speaker: speaker,
content: content,
type: CONST.CHAT_MESSAGE_TYPES.OTHER,
})
}
/**
* Open the Tarot Deck Manager application
* @returns {HamalronTarotDeckManager}
+17 -10
View File
@@ -76,12 +76,16 @@ export default class HamalronTirageTarot {
// Marquer les cartes de succès
if (options.tarotCards && actor.system.cartesSucces) {
const competenceSymbole = options.rollItem.system.carteSymbole
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()
})
// Pour qu'une carte soit une carte de succès :
// 1. Elle ne doit pas être un atout
// 2. Son symbole doit correspondre à celui de la compétence
// 3. Sa valeur doit correspondre à celle d'une carte de succès pour ce symbole
const isSuccessCard = card.system.type !== "atout" &&
card.system.symbole === competenceSymbole &&
actor.system.cartesSucces[competenceSymbole] &&
card.system.valeur === actor.system.cartesSucces[competenceSymbole].value.toString()
// Créer un objet simple avec toutes les propriétés nécessaires
return {
id: card.id,
@@ -339,12 +343,15 @@ export default class HamalronTirageTarot {
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)
// Pour qu'une carte soit une carte de succès :
// 1. Elle ne doit pas être un atout
// 2. Son symbole doit correspondre à celui de la compétence
// 3. Sa valeur doit correspondre à celle d'une carte de succès pour ce symbole
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()
})
const competenceSymbole = options.rollItem.system.carteSymbole
isAutomaticSuccess = selectedCard.system.symbole === competenceSymbole &&
actor.system.cartesSucces[competenceSymbole] &&
selectedCard.system.valeur === actor.system.cartesSucces[competenceSymbole].value.toString()
}
}
}
+1
View File
@@ -44,6 +44,7 @@ export default class HamalronPersonnage extends foundry.abstract.TypeDataModel {
hair: new fields.StringField({ required: true, nullable: false, initial: "" }),
home: new fields.StringField({ required: true, nullable: false, initial: "" }),
weight: new fields.StringField({ required: true, nullable: false, initial: "" }),
origineSociale: new fields.StringField({ required: true, nullable: false, initial: "" }),
})
return schema