feat(experience): atout Socle de compétences — +1D gratuit dans le dialogue d'apprentissage
This commit is contained in:
@@ -517,6 +517,8 @@
|
|||||||
"characteristic_hint": "Difficulty 9 + Handicap = current value. Max 3 (except Superhuman).",
|
"characteristic_hint": "Difficulty 9 + Handicap = current value. Max 3 (except Superhuman).",
|
||||||
"reserve_hint": "Difficulty = current value + age Handicap. Max 10.",
|
"reserve_hint": "Difficulty = current value + age Handicap. Max 10.",
|
||||||
"evolution_hint": "Difficulty by age + Handicap = accumulated Evolution dice. Adapted totem +1D, Human -1D.",
|
"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).",
|
"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.",
|
"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).",
|
"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).",
|
||||||
|
|||||||
@@ -500,6 +500,8 @@
|
|||||||
"characteristic_hint": "Difficulté 9 + Handicap = valeur actuelle. Max 3 (Surhumain excepté).",
|
"characteristic_hint": "Difficulté 9 + Handicap = valeur actuelle. Max 3 (Surhumain excepté).",
|
||||||
"reserve_hint": "Difficulté = valeur actuelle + Handicap d'âge. Max 10.",
|
"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.",
|
"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).",
|
"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.",
|
"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).",
|
"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).",
|
||||||
|
|||||||
@@ -145,6 +145,20 @@ export default class LearningDialog extends HandlebarsApplicationMixin(foundry.a
|
|||||||
return { total: items.length, byLevel };
|
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() {
|
async _onRender() {
|
||||||
this.element.dataset.actorId = this.#actor.id;
|
this.element.dataset.actorId = this.#actor.id;
|
||||||
for (const inp of this.element.querySelectorAll("[data-roll]")) {
|
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));
|
label = game.i18n.localize(VermineExperience.skillLevelLabelKey(targetLevel));
|
||||||
const diff = VermineExperience.skillLearningDifficulty(targetLevel);
|
const diff = VermineExperience.skillLearningDifficulty(targetLevel);
|
||||||
const domain = key ? VermineExperience.isPreferredDomain(actor, key) : false;
|
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 {
|
return {
|
||||||
type,
|
type,
|
||||||
key,
|
key,
|
||||||
targetLevel,
|
targetLevel,
|
||||||
difficulty: domain ? Math.max(3, diff - 2) : diff,
|
difficulty: domain ? Math.max(3, diff - 2) : diff,
|
||||||
handicap: VermineExperience.skillLearningHandicap(targetLevel, rarity),
|
handicap: VermineExperience.skillLearningHandicap(targetLevel, rarity),
|
||||||
poolModifier: 0,
|
poolModifier: socleBonus,
|
||||||
|
socleBonus,
|
||||||
label,
|
label,
|
||||||
targetLabel: key ? game.i18n.localize("SKILLS." + key + ".name") : ""
|
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("#diff-value", c.difficulty);
|
||||||
set("#handicap-value", c.handicap);
|
set("#handicap-value", c.handicap);
|
||||||
set("#required-value", 1 + 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);
|
const pool = Math.max(0, this.#getDiceSpent() + c.poolModifier);
|
||||||
let poolText = `${pool}D${c.poolModifier ? ` (${c.poolModifier >= 0 ? "+" : ""}${c.poolModifier}D)` : ""}`;
|
let poolText = `${pool}D${c.poolModifier ? ` (${c.poolModifier >= 0 ? "+" : ""}${c.poolModifier}D)` : ""}`;
|
||||||
if (c.adaptedDie) poolText += " — " + game.i18n.localize("VERMINE.adapted_die_x2");
|
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) {
|
if ((roll._total ?? 0) >= required) {
|
||||||
await this.#applySuccess(c, specialtyName, roll._total ?? 0);
|
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é.
|
// 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) });
|
await actor.update({ "system.experience.dice": Math.max(0, (actor.system.experience.dice || 0) - spent) });
|
||||||
this.close();
|
this.close();
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
</option>
|
</option>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</select>
|
</select>
|
||||||
|
<p class="learning-hint" id="socle-bonus-hint" style="display:none;"></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="learning-specialty-section" class="learning-targets" style="display:none;">
|
<div id="learning-specialty-section" class="learning-targets" style="display:none;">
|
||||||
|
|||||||
Reference in New Issue
Block a user