diff --git a/lang/en.json b/lang/en.json index 157a274..1d81094 100644 --- a/lang/en.json +++ b/lang/en.json @@ -517,6 +517,8 @@ "characteristic_hint": "Difficulty 9 + Handicap = current value. Max 3 (except Superhuman).", "reserve_hint": "Difficulty = current value + age Handicap. Max 10.", "evolution_hint": "Difficulty by age + Handicap = accumulated Evolution dice. Adapted totem +1D, Human -1D.", + "socle_competences_hint": "Socle de compétences atout: +{level} free Experience die (skill already possessed).", + "socle_competences_message": "Socle de compétences: +{level} free Experience die. Reminder: a Group companion who learns or develops with him a skill he possesses also gains 1 Experience die.", "totem_ability_hint": "Prerequisites: same Totem as the character, Group level ≥ Capacity level, game mode compatible (Survival N1, Nightmare N2, Apocalypse N3).", "background_hint": "Difficulty 9. Handicap (I) if the Background is marked with an asterisk (*). GM authorization required.", "reputation_hint": "Reduce = more famous (Difficulty 10 − target score, 1 pt max per phase). Increase = fade into obscurity (requires a major Objective, Difficulty = current Reputation, +1 per Success).", diff --git a/lang/fr.json b/lang/fr.json index 84c1a7e..a23601c 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -500,6 +500,8 @@ "characteristic_hint": "Difficulté 9 + Handicap = valeur actuelle. Max 3 (Surhumain excepté).", "reserve_hint": "Difficulté = valeur actuelle + Handicap d'âge. Max 10.", "evolution_hint": "Difficulté selon l'âge + Handicap = Dés d'Évolution accumulés. Totem Adapté +1D, Humain -1D.", + "socle_competences_hint": "Atout Socle de compétences : +{level}D d'Expérience gratuit (compétence déjà possédée).", + "socle_competences_message": "Socle de compétences : +{level}D d'Expérience gratuit. Rappel : un camarade du Groupe qui apprend ou développe avec lui une Compétence qu'il possède gagne aussi 1D d'Expérience.", "totem_ability_hint": "Prérequis : même Totem que le personnage, Niveau de Groupe ≥ Niveau de la Capacité, Mode de jeu compatible (Survie N1, Cauchemar N2, Apocalypse N3).", "background_hint": "Difficulté 9. Handicap (I) si l'Historique est marqué d'un astérisque (*). Autorisation du MJ requise.", "reputation_hint": "Réduire = plus célèbre (Difficulté 10 − score visé, 1 pt max/phase). Augmenter = se faire oublier (exige un Objectif majeur, Difficulté = Réputation actuelle, +1 par Réussite).", diff --git a/module/system/dialogs/learningDialog.mjs b/module/system/dialogs/learningDialog.mjs index 9f641bc..98f30b1 100644 --- a/module/system/dialogs/learningDialog.mjs +++ b/module/system/dialogs/learningDialog.mjs @@ -145,6 +145,20 @@ export default class LearningDialog extends HandlebarsApplicationMixin(foundry.a return { total: items.length, byLevel }; } + /** + * Bonus de l'atout "Socle de compétences" (règles p. 112). + * Rend le niveau (1-3) de l'atout possédé par le personnage, ou 0. + * @returns {number} + */ + #socleCompetencesBonus() { + const item = (this.#actor.itemTypes?.ability || []).find(i => + i.system?.type === "character" + && (i.name || "").trim().toLowerCase() === "socle de compétences".toLowerCase() + ); + if (!item) return 0; + return Math.min(3, Math.max(1, parseInt(item.system?.level?.value, 10) || 1)); + } + async _onRender() { this.element.dataset.actorId = this.#actor.id; for (const inp of this.element.querySelectorAll("[data-roll]")) { @@ -201,13 +215,16 @@ export default class LearningDialog extends HandlebarsApplicationMixin(foundry.a label = game.i18n.localize(VermineExperience.skillLevelLabelKey(targetLevel)); const diff = VermineExperience.skillLearningDifficulty(targetLevel); const domain = key ? VermineExperience.isPreferredDomain(actor, key) : false; + // Atout "Socle de compétences" : 1D gratuit si la Compétence est déjà possédée. + const socleBonus = current >= 1 ? this.#socleCompetencesBonus() : 0; return { type, key, targetLevel, difficulty: domain ? Math.max(3, diff - 2) : diff, handicap: VermineExperience.skillLearningHandicap(targetLevel, rarity), - poolModifier: 0, + poolModifier: socleBonus, + socleBonus, label, targetLabel: key ? game.i18n.localize("SKILLS." + key + ".name") : "" }; @@ -363,6 +380,15 @@ export default class LearningDialog extends HandlebarsApplicationMixin(foundry.a set("#diff-value", c.difficulty); set("#handicap-value", c.handicap); set("#required-value", 1 + c.handicap); + const socleHint = this.#el.querySelector("#socle-bonus-hint"); + if (socleHint) { + if (type === "skill" && c.socleBonus > 0) { + socleHint.style.display = ""; + socleHint.textContent = game.i18n.format("VERMINE.socle_competences_hint", { level: c.socleBonus }); + } else { + socleHint.style.display = "none"; + } + } const pool = Math.max(0, this.#getDiceSpent() + c.poolModifier); let poolText = `${pool}D${c.poolModifier ? ` (${c.poolModifier >= 0 ? "+" : ""}${c.poolModifier}D)` : ""}`; if (c.adaptedDie) poolText += " — " + game.i18n.localize("VERMINE.adapted_die_x2"); @@ -496,6 +522,14 @@ export default class LearningDialog extends HandlebarsApplicationMixin(foundry.a if ((roll._total ?? 0) >= required) { await this.#applySuccess(c, specialtyName, roll._total ?? 0); } + // Atout "Socle de compétences" : rappeler le bonus conféré aux camarades + // du Groupe qui apprennent une Compétence possédée par le personnage. + if (c.socleBonus > 0) { + await ChatMessage.create({ + content: game.i18n.format("VERMINE.socle_competences_message", { level: c.socleBonus }), + speaker: ChatMessage.getSpeaker({ actor }) + }); + } // Les Dés d'Expérience sont perdus que le jet soit réussi ou raté. await actor.update({ "system.experience.dice": Math.max(0, (actor.system.experience.dice || 0) - spent) }); this.close(); diff --git a/templates/dialogs/learning-dialog.hbs b/templates/dialogs/learning-dialog.hbs index 580036f..bd517c0 100644 --- a/templates/dialogs/learning-dialog.hbs +++ b/templates/dialogs/learning-dialog.hbs @@ -26,6 +26,7 @@ {{/each}} +