diff --git a/modules/mournblade-cyd2-actor.js b/modules/mournblade-cyd2-actor.js index d1f262c..2bf1453 100644 --- a/modules/mournblade-cyd2-actor.js +++ b/modules/mournblade-cyd2-actor.js @@ -145,6 +145,12 @@ export class MournbladeCYD2Actor extends Actor { getRunes() { return this.getItemSorted(["rune"]) } + getRuneEffects() { + return this.getItemSorted(["runeeffect"]) + } + getProfil() { + return this.getProfils()[0] ?? null + } getTraitsChaotiques() { return this.getItemSorted(["traitchaotique"]) } @@ -220,6 +226,9 @@ export class MournbladeCYD2Actor extends Actor { } return equipProtection // Uniquement la protection des armures + boucliers } + getProtectionTotal() { + return this.getProtection() + } /* -------------------------------------------- */ getCombatValues() { @@ -267,12 +276,13 @@ export class MournbladeCYD2Actor extends Actor { /* -------------------------------------------- */ _preUpdate(changed, options, user) { - if (changed?.system?.sante?.etat && changed?.system?.sante?.etat != this.system.sante.etat) { + if (changed?.system?.sante?.etat !== undefined && changed.system.sante.etat != this.system.sante.etat) { + const oldEtat = this.system.sante.etat setTimeout(() => { - this.processCombativite(changed.system.sante) + this.processCombativite(changed.system.sante, oldEtat) }, 800) } - if (changed?.system?.ame?.etat && changed?.system?.ame?.etat != this.system.ame.etat) { + if (changed?.system?.ame?.etat !== undefined && changed.system.ame.etat != this.system.ame.etat) { // L'état d'Âme ne peut pas être inférieur au minimum (max dans le système) let minAme = this.system.ame.max !== undefined ? this.system.ame.max : 0 if (changed.system.ame.etat < minAme) { @@ -282,8 +292,9 @@ export class MournbladeCYD2Actor extends Actor { if (changed.system.ame.etat > this.system.ame.nbame) { changed.system.ame.etat = this.system.ame.nbame } + const oldEtat = this.system.ame.etat setTimeout(() => { - this.processAme(changed.system.ame) + this.processAme(changed.system.ame, oldEtat) }, 800) } // Si le max d'Âme change, ajuster l'état actuel si nécessaire @@ -500,38 +511,57 @@ export class MournbladeCYD2Actor extends Actor { } /* -------------------------------------------- */ - processCombativite(sante) { + processCombativite(sante, oldEtat = undefined) { sante = sante || foundry.utils.duplicate(this.system.sante) - // Gestion des états affaibli et très affaibli - if (sante.etat == this.system.sante.nbcombativite - 2 || sante.etat == this.system.sante.nbcombativite - 1) { - if (sante.etat == this.system.sante.nbcombativite - 2 && this.items.find(item => item.type == "talent" && item.name.toLowerCase() == "encaissement")) { - ChatMessage.create({ content: `${this.name} ne subit pas les 2 adversités rouge grâce à Encaissement. Pensez à les ajouter à la fin de la scène !` }) - } else if (sante.etat == this.system.sante.nbcombativite - 1 && this.items.find(item => item.type == "talent" && item.name.toLowerCase().includes("vaillant"))) { - ChatMessage.create({ content: `${this.name} ne subit pas les 2 adversités rouge grâce à Vaillant. Pensez à les ajouter à la fin de la scène !` }) + const affaibli = this.system.sante.nbcombativite - 2 + const tresAffaibli = this.system.sante.nbcombativite - 1 + // oldEtat permet de détecter les sauts qui franchissent Affaibli ou Très Affaibli + // sans y atterrir exactement (ex: 0 → 5 doit déclencher les deux seuils) + const prev = oldEtat !== undefined ? oldEtat : sante.etat + const curr = sante.etat + + const passedAffaibli = curr >= affaibli && prev < affaibli + const passedTresAffaibli = curr >= tresAffaibli && prev < tresAffaibli + + if (passedAffaibli) { + if (this.items.find(item => item.type == "talent" && item.name.toLowerCase() == "encaissement")) { + ChatMessage.create({ content: `${this.name} ne subit pas les 2 adversités rouge (Affaibli) grâce à Encaissement. Pensez à les ajouter à la fin de la scène !` }) } else { - ChatMessage.create({ content: `${this.name} subit 2 adversités rouge !` }) + ChatMessage.create({ content: `${this.name} est Affaibli et subit 2 adversités rouge !` }) + this.incDecAdversite("rouge", 2) + } + } + if (passedTresAffaibli) { + if (this.items.find(item => item.type == "talent" && item.name.toLowerCase().includes("vaillant"))) { + ChatMessage.create({ content: `${this.name} ne subit pas les 2 adversités rouge (Très Affaibli) grâce à Vaillant. Pensez à les ajouter à la fin de la scène !` }) + } else { + ChatMessage.create({ content: `${this.name} est Très Affaibli et subit 2 adversités rouge supplémentaires !` }) this.incDecAdversite("rouge", 2) } } } /* -------------------------------------------- */ - processAme(ame) { + processAme(ame, oldEtat = undefined) { ame = ame || foundry.utils.duplicate(this.system.ame) - let traumatiseValue = this.system.ame.nbame - 2 - let tresTraumatiseValue = this.system.ame.nbame - 1 - let briseValue = this.system.ame.nbame + const traumatiseValue = this.system.ame.nbame - 2 + const tresTraumatiseValue = this.system.ame.nbame - 1 + const briseValue = this.system.ame.nbame + const prev = oldEtat !== undefined ? oldEtat : ame.etat + const curr = ame.etat - // Gestion des états Traumatisé, Très Traumatisé et Brisé - if (ame.etat == traumatiseValue) { + // Déclencher pour chaque seuil franchi ou atteint, même en cas de saut + if (curr >= traumatiseValue && prev < traumatiseValue) { ChatMessage.create({ content: `${this.name} est Traumatisé et subit 1 adversité bleue et 1 adversité noire !` }) this.incDecAdversite("bleue", 1) this.incDecAdversite("noire", 1) - } else if (ame.etat == tresTraumatiseValue) { + } + if (curr >= tresTraumatiseValue && prev < tresTraumatiseValue) { ChatMessage.create({ content: `${this.name} est Très Traumatisé et subit 1 adversité bleue et 1 adversité noire !` }) this.incDecAdversite("bleue", 1) this.incDecAdversite("noire", 1) - } else if (ame.etat >= briseValue) { + } + if (curr >= briseValue && prev < briseValue) { ChatMessage.create({ content: `${this.name} est Brisé et subit 1 adversité noire !` }) this.incDecAdversite("noire", 1) } @@ -858,14 +888,11 @@ export class MournbladeCYD2Actor extends Actor { roll = await new Roll("1d10+" + arme.system.totalDegats + "+" + bonus + "+" + bonus2).roll() } await MournbladeCYD2Utility.showDiceSoNice(roll, game.settings.get("core", "rollMode")); - // CYD 2.0: dégâts ≥ SV → -2 combativité; ≥ 2×SV → -3 combativité + // CYD 2.0: états SUPPLÉMENTAIRES au-delà du -1 automatique à la réussite. + // Math.floor(total/SV) = 0 (= 2 * targetVigueur) { - nbEtatPerdus = 3 - } else if (roll.total >= targetVigueur) { - nbEtatPerdus = 2 - } + nbEtatPerdus = Math.floor(roll.total / targetVigueur) } //console.log(roll) let rollData = { diff --git a/modules/mournblade-cyd2-config.js b/modules/mournblade-cyd2-config.js index 925e117..ff95f8b 100644 --- a/modules/mournblade-cyd2-config.js +++ b/modules/mournblade-cyd2-config.js @@ -125,5 +125,23 @@ export const MOURNBLADECYD2_CONFIG = { { key: "vigueur", label: "Vigueur" }, { key: "seuilpouvoir", label: "Seuil de Pouvoir" }, { key: "bonus-defensif", label: "Bonus au Seuil de Défense" } + ], + etatsCombativite: [ + { key: 0, label: "Combatif" }, + { key: 1, label: "Éprouvé 1" }, + { key: 2, label: "Éprouvé 2" }, + { key: 3, label: "Affaibli" }, + { key: 4, label: "Très Affaibli" }, + { key: 5, label: "Vaincu" } + ], + etatsAme: [ + { key: 0, label: "Serein" }, + { key: 1, label: "Stressé 1" }, + { key: 2, label: "Stressé 2" }, + { key: 3, label: "Stressé 3" }, + { key: 4, label: "Stressé 4" }, + { key: 5, label: "Traumatisé" }, + { key: 6, label: "Très Traumatisé" }, + { key: 7, label: "Brisé" } ] } \ No newline at end of file diff --git a/modules/mournblade-cyd2-main.js b/modules/mournblade-cyd2-main.js index a272fbe..b604f07 100644 --- a/modules/mournblade-cyd2-main.js +++ b/modules/mournblade-cyd2-main.js @@ -167,7 +167,7 @@ Hooks.on("chatMessage", (html, content, msg) => { if (content[0] == '/') { let regExp = /(\S+)/g; let commands = content.match(regExp); - if (game.system.mournblade.commands.processChatCommand(commands, content, msg)) { + if (game.system.mournbladecyd2.commands?.processChatCommand(commands, content, msg)) { return false; } } diff --git a/modules/mournblade-cyd2-utility.js b/modules/mournblade-cyd2-utility.js index 58c7112..cf232c0 100644 --- a/modules/mournblade-cyd2-utility.js +++ b/modules/mournblade-cyd2-utility.js @@ -767,6 +767,15 @@ export class MournbladeCYD2Utility { this.createChatMessage(name, game.settings.get("core", "rollMode"), chatOptions, rollData) } + /* -------------------------------------------- */ + static getActorAlignment(actor) { + const loi = actor.system?.balance?.loi ?? 0 + const chaos = actor.system?.balance?.chaos ?? 0 + if (loi > chaos) return 'loyal' + if (chaos > loi) return 'chaotique' + return 'neutre' + } + /* -------------------------------------------- */ static applyBonneAventureRoll(li, changed, addedBonus) { let msgId = $(li).data("message-id") @@ -808,42 +817,67 @@ export class MournbladeCYD2Utility { /* -------------------------------------------- */ static chatRollMenu(html, options) { let canApply = li => canvas.tokens.controlled.length && li.find(".mournblade-cyd2-roll").length - let canApplyBA = function (li) { + let getActor = function (li) { let message = game.messages.get($(li).attr("data-message-id")) let rollData = message.getFlag("world", "mournblade-cyd2-roll") + return MournbladeCYD2Utility.getActorFromRollData(rollData) + } + let getRollData = function (li) { + let message = game.messages.get($(li).attr("data-message-id")) + return message.getFlag("world", "mournblade-cyd2-roll") + } + let canApplyBA = function (li) { + let rollData = getRollData(li) let actor = MournbladeCYD2Utility.getActorFromRollData(rollData) return (!rollData.isReroll && actor.getBonneAventure() > 0) } let canApplyPE = function (li) { - let message = game.messages.get($(li).attr("data-message-id")) - let rollData = message.getFlag("world", "mournblade-cyd2-roll") + let rollData = getRollData(li) let actor = MournbladeCYD2Utility.getActorFromRollData(rollData) return (!rollData.isReroll && actor.getEclat() > 0) } - options.push( - { - name: "Ajouer +3 (1 point de Bonne Aventure)", - icon: "", - condition: canApply && canApplyBA, - callback: li => MournbladeCYD2Utility.applyBonneAventureRoll(li, -1, "+3") - } - ) - options.push( - { - name: "Ajouter +10 (1 Point d'Eclat)", - icon: "", - condition: canApply && canApplyPE, - callback: li => MournbladeCYD2Utility.applyEclatRoll(li, -1, "+10") - } - ) - options.push( - { - name: "Relancer le dé (1 point d'Eclat)", - icon: "", - condition: canApply && canApplyPE, - callback: li => MournbladeCYD2Utility.applyEclatRoll(li, -1, "reroll") - } - ) + let isLoyal = function (li) { + return MournbladeCYD2Utility.getActorAlignment(getActor(li)) === 'loyal' + } + let isChaotique = function (li) { + return MournbladeCYD2Utility.getActorAlignment(getActor(li)) === 'chaotique' + } + + // Bonne Aventure — loyal : +3 fixe + options.push({ + name: "Ajouter +3 (1 point de Bonne Aventure — Loyal)", + icon: "", + condition: li => canApply(li) && canApplyBA(li) && !isChaotique(li), + callback: li => MournbladeCYD2Utility.applyBonneAventureRoll(li, -1, "+3") + }) + // Bonne Aventure — chaotique : +1d6 + options.push({ + name: "Ajouter +1d6 (1 point de Bonne Aventure — Chaotique)", + icon: "", + condition: li => canApply(li) && canApplyBA(li) && !isLoyal(li), + callback: li => MournbladeCYD2Utility.applyBonneAventureRoll(li, -1, "+1d6") + }) + // Éclat — loyal : +10 + options.push({ + name: "Ajouter +10 (1 point d'Éclat — Loyal)", + icon: "", + condition: li => canApply(li) && canApplyPE(li) && !isChaotique(li), + callback: li => MournbladeCYD2Utility.applyEclatRoll(li, -1, "+10") + }) + // Éclat — chaotique : +1d20 + options.push({ + name: "Ajouter +1d20 (1 point d'Éclat — Chaotique)", + icon: "", + condition: li => canApply(li) && canApplyPE(li) && !isLoyal(li), + callback: li => MournbladeCYD2Utility.applyEclatRoll(li, -1, "+1d20") + }) + // Éclat — relancer (tous) + options.push({ + name: "Relancer le dé (1 point d'Éclat)", + icon: "", + condition: li => canApply(li) && canApplyPE(li), + callback: li => MournbladeCYD2Utility.applyEclatRoll(li, -1, "reroll") + }) return options }