feat: nouveaux apprentissages (Capacités de Totem, Historique, Réputation) et expérience de Groupe
- Dialogue d'apprentissage personnage : 4 nouveaux types d'achat.
- Capacité de Totem : options filtrées (mode de jeu, niveau de
groupe, totem, non-apprises), difficulté = valeur d'Apprentissage,
limites 3×N1 / 1×N2-N3 / max 5, marque system.learned de l'item
(convention type character) et learned.ability du personnage.
- Élément d'Historique : difficulté 9, handicap 1 si astérisque
(background.asterisk), marque learned.background + item.
- Test de Réputation (réduire/augmenter) : réduire = difficulté
10 − score visé (−1 pt), augmenter = difficulté = réputation
actuelle (+1 par succès), bornes 0-10, marque learned.reputation.
- Évolution : option Dé de Totem Adapté ×2 quand Adapté > Humain
(1D remplacé par un dé adapté compté ×2 via VermineUtils.roll).
- Correction règles : les Dés d'Expérience sont dépensés même en cas
d'échec du jet d'apprentissage (décompte hors #applySuccess).
- Expérience de Groupe : nouveau dialogue d'apprentissage de Groupe
(niveau, réserve, capacité de totem), réserve d'expérience et phase
dans system.experience, boutons sur la fiche Groupe, reset des
limites par phase (level/reserve/ability).
- Phase d'expérience : filtre par groupe sélectionné, associe chaque
personnage à son premier groupe, reset des limites de tous les
nouveaux types d'apprentissage.
- Corrections : l'attaque de créature n'ajoute plus la Réaction du Rôle
(regles_creatures.txt), suppression de la case XP des en-têtes PJ
(legacy et AppV2).
- Divers : .eslintrc.js (règles inexistantes/obsolètes retirées),
libellé jaune de dialogue en couleur chitine, i18n FR/EN, chips
« appris » sur l'onglet expérience du personnage.
This commit is contained in:
@@ -41,11 +41,19 @@ export default class ExperiencePhaseDialog extends HandlebarsApplicationMixin(fo
|
||||
async _prepareContext() {
|
||||
const characters = game.actors.filter(a => a.type === "character");
|
||||
const groups = game.actors.filter(a => a.type === "group");
|
||||
// Associe chaque personnage à son premier groupe (même logique que RollDialog.#findGroup)
|
||||
const memberOf = new Map();
|
||||
for (const g of groups) {
|
||||
for (const id of g.system?.members || []) {
|
||||
if (!memberOf.has(id)) memberOf.set(id, g.id);
|
||||
}
|
||||
}
|
||||
return {
|
||||
characters: characters.map(a => ({
|
||||
id: a.id,
|
||||
name: a.name,
|
||||
dice: a.system?.experience?.dice || 0
|
||||
dice: a.system?.experience?.dice || 0,
|
||||
groupId: memberOf.get(a.id) || ""
|
||||
})),
|
||||
groups: groups.map(a => ({
|
||||
id: a.id,
|
||||
@@ -63,7 +71,9 @@ export default class ExperiencePhaseDialog extends HandlebarsApplicationMixin(fo
|
||||
|
||||
async _onRender(context, options) {
|
||||
this.element.querySelectorAll("[data-roll]").forEach(inp => inp.addEventListener("change", () => this.#updateUI()));
|
||||
this.element.querySelector("#group-select")?.addEventListener("change", () => this.#updateGroupFilter());
|
||||
this.#updateUI();
|
||||
this.#updateGroupFilter();
|
||||
}
|
||||
|
||||
#updateUI() {
|
||||
@@ -74,6 +84,15 @@ export default class ExperiencePhaseDialog extends HandlebarsApplicationMixin(fo
|
||||
if (el) el.textContent = `${danger + discoveries + duration}D`;
|
||||
}
|
||||
|
||||
/** Filtre les personnages selon le groupe sélectionné (vide = tous). */
|
||||
#updateGroupFilter() {
|
||||
const groupId = this.element.querySelector("#group-select")?.value || "";
|
||||
for (const row of this.element.querySelectorAll("[data-character-id]")) {
|
||||
const show = !groupId || row.dataset.groupId === groupId;
|
||||
row.hidden = !show;
|
||||
}
|
||||
}
|
||||
|
||||
static async #onCancel(event, target) {
|
||||
this.close();
|
||||
}
|
||||
@@ -88,12 +107,22 @@ export default class ExperiencePhaseDialog extends HandlebarsApplicationMixin(fo
|
||||
const group = game.actors.get(groupId);
|
||||
if (group && collective > 0) {
|
||||
const current = group.system?.experience?.dice || 0;
|
||||
await group.update({ "system.experience.dice": current + collective });
|
||||
const phase = (group.system?.experience?.phase || 0) + 1;
|
||||
await group.update({
|
||||
"system.experience.dice": current + collective,
|
||||
"system.experience.phase": phase,
|
||||
"system.experience.learned.phase": phase,
|
||||
"system.experience.learned.level": false,
|
||||
"system.experience.learned.reserve": false,
|
||||
"system.experience.learned.ability": false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const results = [];
|
||||
for (const row of this.element.querySelectorAll("[data-character-id]")) {
|
||||
// Quand un groupe précis est choisi, ne récompenser que ses membres.
|
||||
if (groupId && row.dataset.groupId !== groupId) continue;
|
||||
const id = row.dataset.characterId;
|
||||
const actor = game.actors.get(id);
|
||||
if (!actor) continue;
|
||||
@@ -125,7 +154,10 @@ export default class ExperiencePhaseDialog extends HandlebarsApplicationMixin(fo
|
||||
"system.experience.learned.specialty": false,
|
||||
"system.experience.learned.reserve": false,
|
||||
"system.experience.learned.characteristic": false,
|
||||
"system.experience.learned.evolution": false
|
||||
"system.experience.learned.evolution": false,
|
||||
"system.experience.learned.ability": false,
|
||||
"system.experience.learned.background": false,
|
||||
"system.experience.learned.reputation": false
|
||||
};
|
||||
await actor.update(update);
|
||||
results.push({ name: actor.name, gained });
|
||||
|
||||
Reference in New Issue
Block a user