refacto: harmonisation du système avec les règles Hamalron JDR

Corrections majeures :
- HamalronTirageTarot extends Roll (évaluation des jets fonctionnelle)
- Correction du nom de classe Langue (HamalronFaction -> HamalronLangue)
- Création du template tab-navigation.hbs manquant
- Type acteur 'character' -> 'personnage' dans _preCreate

Types d'items corrigés (anglais -> français) :
- weapon -> arme, armor -> armure, equipment -> equipement
- Suppression des types inexistants (deal, malefica, ritual, perk)

Modèles :
- cost -> cout (armure, equipement)
- Tarot : default -> initial
- Sortilege : LOCALIZATION_PREFIXES corrigé
- Constantes CHOICE_ADVANTAGES_DISADVANTAGES et ATTACK_MODIFIERS ajoutées
- ATTACK_MODIFIERS supprimé (plus utilisé)

Templates alignés sur les modèles réels :
- enemy-trait : suppression champs manquants (trauma, stats, domain...)
- personnage-equipement : champs alignés sur arme/armure/equipement
- personnage-sortileges : suppression domain/level/rituals
- enemy-main : suppression stats et flavorText
- base-actor : suppression mortality, toChat limité aux tarots

Jets de compétence :
- Égalité = réussite (>= au lieu de >, conforme aux règles p.155)
- Comparaison robuste des cartes de succès (via String())

Le Mat :
- Les autres joueurs peuvent renouveler leur main (règle p.151)

findTarotItem : recherche dans game.items puis compendiums
await manquants ajoutés sur saveDeckState()
AGENTS.md créé
This commit is contained in:
2026-07-10 18:52:20 +02:00
parent 4bc381f2e6
commit 68b3079da8
25 changed files with 257 additions and 570 deletions
+53 -60
View File
@@ -1,7 +1,8 @@
import { SYSTEM } from "../config/system.mjs"
import HamalronUtils from "../utils.mjs"
export default class HamalronTirageTarot {
export default class HamalronTirageTarot extends Roll {
/**
* The HTML template path used to render dice checks of this type
* @type {string}
@@ -41,7 +42,7 @@ export default class HamalronTirageTarot {
const newCards = deckManager.drawCards(1)
if (newCards.length > 0) {
const newCard = newCards[0]
const originalItem = game.items.get(newCard.id)
const originalItem = await HamalronUtils.findTarotItem(newCard)
if (originalItem) {
await actor.createEmbeddedDocuments("Item", [originalItem.toObject()])
}
@@ -50,12 +51,42 @@ export default class HamalronTirageTarot {
}
// 3. Regrouper la défausse et le deck, puis mélanger
deckManager.deck.push(...deckManager.discard)
deckManager.discard = []
deckManager.shuffleDeck()
await deckManager.saveDeckState()
await deckManager.resetDeck()
deckManager.render()
// 4. Proposer aux autres joueurs de renouveler leur main
if (game.user.isGM) {
const refreshOthers = await foundry.applications.api.DialogV2.confirm({
window: { title: "Le Mat - Renouvellement" },
content: `<p>Le Mat a été tiré ! Les autres joueurs peuvent renouveler leur main s'ils le désirent.</p>`,
rejectClose: false,
modal: true,
})
if (refreshOthers) {
for (const otherActor of game.actors.filter(a => a.type === "personnage")) {
if (otherActor.id === actor.id) continue
const otherCards = otherActor.items.filter(i => i.type === "tarot")
if (otherCards.length > 0) {
const otherCardIds = otherCards.map(c => c.id)
await otherActor.deleteEmbeddedDocuments("Item", otherCardIds)
for (let i = 0; i < 7; i++) {
if (deckManager.deck.length > 0) {
const newCards = deckManager.drawCards(1)
if (newCards.length > 0) {
const originalItem = await HamalronUtils.findTarotItem(newCards[0])
if (originalItem) {
await otherActor.createEmbeddedDocuments("Item", [originalItem.toObject()])
}
}
}
}
}
}
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é.`)
}
@@ -78,14 +109,10 @@ export default class HamalronTirageTarot {
if (options.tarotCards && actor.system.cartesSucces) {
const competenceSymbole = options.rollItem.system.carteSymbole
options.tarotCards = options.tarotCards.map(card => {
// 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()
String(card.system.valeur) === String(actor.system.cartesSucces[competenceSymbole].value)
// Créer un objet simple avec toutes les propriétés nécessaires
return {
id: card.id,
@@ -103,8 +130,10 @@ export default class HamalronTirageTarot {
let formula = options.rollItem.system.damage
if (options.rollItem?.system?.damageStat && options.rollItem.system.damageStat !== "none" && options.rollItem.system.damageStat !== "") {
let statKey = options.rollItem.system?.damageStat.toLowerCase()
let statValue = actor.system.stats[statKey].value
formula = `${formula} + ${statValue}`
let statValue = actor.system?.stats?.[statKey]?.value
if (statValue != null) {
formula = `${formula} + ${statValue}`
}
}
let damageRoll = new Roll(formula)
await damageRoll.evaluate()
@@ -117,8 +146,10 @@ export default class HamalronTirageTarot {
case "weapon":
{
options.weapon = foundry.utils.duplicate(options.rollItem)
let statKey = options.weapon.system.stat.toLowerCase()
options.rollItem = actor.system.stats[statKey]
let statKey = options.weapon.system?.stat?.toLowerCase()
if (statKey && actor.system?.stats?.[statKey]) {
options.rollItem = actor.system.stats[statKey]
}
}
break
default:
@@ -200,25 +231,6 @@ export default class HamalronTirageTarot {
},
rejectClose: false, // Click on Close button will not launch an error
render: (event, dialog) => {
$(".roll-stat-advantages").change(event => {
options.nbAdvantages = Number(event.target.value)
HamalronTirageTarot.updateFullFormula(options)
})
$(".roll-stat-disadvantages").change(event => {
options.nbDisadvantages = Number(event.target.value)
HamalronTirageTarot.updateFullFormula(options)
})
$(".select-combat-option").change(event => {
let field = $(event.target).data("field")
let modifier = SYSTEM.ATTACK_MODIFIERS[field]
if (event.target.checked) {
options.numericModifier += modifier
} else {
options.numericModifier -= modifier
}
HamalronTirageTarot.updateFullFormula(options)
})
// Gestion de la sélection de carte pour les compétences
if (options.rollType === "competence") {
let selectedCardId = null
@@ -342,16 +354,11 @@ export default class HamalronTirageTarot {
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)
// 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") {
const competenceSymbole = options.rollItem.system.carteSymbole
isAutomaticSuccess = selectedCard.system.symbole === competenceSymbole &&
actor.system.cartesSucces[competenceSymbole] &&
selectedCard.system.valeur === actor.system.cartesSucces[competenceSymbole].value.toString()
String(selectedCard.system.valeur) === String(actor.system.cartesSucces[competenceSymbole].value)
}
}
}
@@ -359,7 +366,7 @@ export default class HamalronTirageTarot {
// 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
const isSuccess = isAutomaticSuccess || totalValue >= options.targetScore
// Détecter si la carte est un valet
const isValet = selectedCard?.system.valeur === "valet"
@@ -468,21 +475,7 @@ export default class HamalronTirageTarot {
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)
}
const originalItem = await HamalronUtils.findTarotItem(newCard)
if (originalItem) {
// Cas spécial : Le Mat
@@ -505,7 +498,7 @@ export default class HamalronTirageTarot {
console.log("Deck is empty, cannot draw new card")
}
deckManager.saveDeckState()
await deckManager.saveDeckState()
deckManager.render()
ui.notifications.info(`${game.i18n.localize("HAMALRON.Notifications.cardUsed")}: ${selectedCard.name}`)
}
@@ -673,7 +666,7 @@ export default class HamalronTirageTarot {
* @returns {Promise} - A promise that resolves when the message is created.
*/
async toMessage(messageData = {}, { rollMode, create = true } = {}) {
super.toMessage(
return super.toMessage(
{
isFailure: this.resultType === "failure",
actingCharName: this.actorName,
@@ -682,7 +675,7 @@ export default class HamalronTirageTarot {
realDamage: this.realDamage,
...messageData,
},
{ rollMode: rollMode },
{ rollMode, create },
)
}