Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ef0de45ff |
+4
-1
@@ -333,6 +333,9 @@
|
||||
"CharacterNamePlaceholder": "Character Name",
|
||||
"ProfilePlaceholder": "Profile",
|
||||
"none": "None",
|
||||
"all_characters": "All characters",
|
||||
"no_group": "No group",
|
||||
"include_in_phase": "Include in this phase",
|
||||
"bonuses": "Bonuses",
|
||||
"choose_ability": "Choose Ability",
|
||||
"choose_skill": "Choose Skill",
|
||||
@@ -469,7 +472,7 @@
|
||||
"mode_survie": "Survival",
|
||||
"mode_cauchemar": "Nightmare",
|
||||
"mode_apocalypse": "Apocalypse",
|
||||
"evolution_buy_hint": "The purchase consumes and erases all accumulated Evolution dice. Limits: Survival 5D, Nightmare 6D, Apocalypse 7D total. Level 3/4 Mutations are forbidden in Survival; only one level 4 Mutation.",
|
||||
"evolution_buy_hint": "The purchase consumes a number of Evolution dice equal to the chosen level (the remainder is kept). Limits: Survival 5D, Nightmare 6D, Apocalypse 7D total. Level 3/4 Mutations are forbidden in Survival; only one level 4 Mutation.",
|
||||
"buy_evolution_done": "Adaptation/Mutation acquired. Evolution dice erased.",
|
||||
"error_evolution_no_name": "Provide a name for the Adaptation/Mutation.",
|
||||
"error_evolution_invalid_level": "Invalid level (1 to 4).",
|
||||
|
||||
+4
-1
@@ -365,6 +365,9 @@
|
||||
"choose_ability": "Choisissez une caractéristique",
|
||||
"choose_skill": "Choisissez une compétence",
|
||||
"none": "Aucun",
|
||||
"all_characters": "Tous les personnages",
|
||||
"no_group": "Sans groupe",
|
||||
"include_in_phase": "Inclure dans cette phase",
|
||||
"total": "Total",
|
||||
"bonuses": "Bonus",
|
||||
"handicap": "Handicap",
|
||||
@@ -452,7 +455,7 @@
|
||||
"mode_survie": "Survie",
|
||||
"mode_cauchemar": "Cauchemar",
|
||||
"mode_apocalypse": "Apocalypse",
|
||||
"evolution_buy_hint": "L'achat consomme et efface tous les Dés d'Évolution accumulés. Limites : Survie 5D, Cauchemar 6D, Apocalypse 7D au total. Mutations 3D/4D interdites en Mode Survie ; une seule Mutation à 4D.",
|
||||
"evolution_buy_hint": "L'achat consomme un nombre de Dés d'Évolution égal au niveau choisi (le reste est conservé). Limites : Survie 5D, Cauchemar 6D, Apocalypse 7D au total. Mutations 3D/4D interdites en Mode Survie ; une seule Mutation à 4D.",
|
||||
"buy_evolution_done": "Adaptation/Mutation acquise. Dés d'Évolution effacés.",
|
||||
"error_evolution_no_name": "Indiquez un nom pour l'Adaptation/Mutation.",
|
||||
"error_evolution_invalid_level": "Niveau invalide (1 à 4).",
|
||||
|
||||
@@ -5,8 +5,8 @@ const { HandlebarsApplicationMixin } = foundry.applications.api;
|
||||
/**
|
||||
* Dialogue d'achat d'une Adaptation/Mutation avec les Dés d'Évolution
|
||||
* accumulés. Vérifie le coût (niveau 1-4), la limite du Mode de jeu et les
|
||||
* restrictions sur les Mutations ; en cas de succès, crée l'item et efface
|
||||
* les Dés d'Évolution accumulés.
|
||||
* restrictions sur les Mutations ; en cas de succès, crée l'item et consomme
|
||||
* un nombre de Dés d'Évolution égal au niveau choisi.
|
||||
*/
|
||||
export default class BuyEvolutionDialog extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) {
|
||||
|
||||
@@ -61,7 +61,7 @@ export default class BuyEvolutionDialog extends HandlebarsApplicationMixin(found
|
||||
};
|
||||
const levels = [];
|
||||
for (let value = 1; value <= 4; value++) {
|
||||
levels.push({ value, cost: value });
|
||||
levels.push({ value });
|
||||
}
|
||||
return {
|
||||
evolutionDice: actor.system?.experience?.evolution || 0,
|
||||
@@ -73,6 +73,18 @@ export default class BuyEvolutionDialog extends HandlebarsApplicationMixin(found
|
||||
};
|
||||
}
|
||||
|
||||
async _onRender() {
|
||||
this.element.querySelectorAll("[data-roll]").forEach(inp => inp.addEventListener("change", () => this.#updateUI()));
|
||||
this.#updateUI();
|
||||
}
|
||||
|
||||
/** Met à jour le total des niveaux « après achat » selon le niveau sélectionné. */
|
||||
#updateUI() {
|
||||
const cost = parseInt(this.element.querySelector("#evolution-level")?.value, 10) || 0;
|
||||
const el = this.element.querySelector("#evolution-total-value");
|
||||
if (el) el.textContent = `${VermineExperience.evolutionTotalLevels(this.#actor) + cost}D`;
|
||||
}
|
||||
|
||||
static async #onCancel(event, target) {
|
||||
this.close();
|
||||
}
|
||||
@@ -102,12 +114,12 @@ export default class BuyEvolutionDialog extends HandlebarsApplicationMixin(found
|
||||
mutation
|
||||
}
|
||||
}]);
|
||||
// N'efface les Dés d'Évolution que si l'item a bien été créé.
|
||||
// Ne consomme que le coût du niveau choisi (Règles p. 116-117 : coût = niveau).
|
||||
if (!created || created.length === 0) {
|
||||
ui.notifications.warn(game.i18n.localize("VERMINE.error_evolution_create"));
|
||||
return;
|
||||
}
|
||||
await actor.update({ "system.experience.evolution": 0 });
|
||||
await actor.update({ "system.experience.evolution": Math.max(0, (actor.system?.experience?.evolution || 0) - cost) });
|
||||
|
||||
ui.notifications.info(game.i18n.localize("VERMINE.buy_evolution_done"));
|
||||
this.close();
|
||||
|
||||
@@ -48,13 +48,18 @@ export default class ExperiencePhaseDialog extends HandlebarsApplicationMixin(fo
|
||||
if (!memberOf.has(id)) memberOf.set(id, g.id);
|
||||
}
|
||||
}
|
||||
const groupById = new Map(groups.map(g => [g.id, g]));
|
||||
return {
|
||||
characters: characters.map(a => ({
|
||||
id: a.id,
|
||||
name: a.name,
|
||||
dice: a.system?.experience?.dice || 0,
|
||||
groupId: memberOf.get(a.id) || ""
|
||||
})),
|
||||
characters: characters.map(a => {
|
||||
const groupId = memberOf.get(a.id) || "";
|
||||
return {
|
||||
id: a.id,
|
||||
name: a.name,
|
||||
dice: a.system?.experience?.dice || 0,
|
||||
groupId,
|
||||
groupName: groupId ? groupById.get(groupId)?.name : ""
|
||||
};
|
||||
}),
|
||||
groups: groups.map(a => ({
|
||||
id: a.id,
|
||||
name: a.name,
|
||||
@@ -72,6 +77,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.element.querySelectorAll("[name^='include-']").forEach(cb =>
|
||||
cb.addEventListener("click", event => event.stopPropagation())
|
||||
);
|
||||
this.#updateUI();
|
||||
this.#updateGroupFilter();
|
||||
}
|
||||
@@ -84,11 +92,16 @@ 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). */
|
||||
/** Filtre les personnages selon le groupe sélectionné (vide = tous, "none" = sans groupe). */
|
||||
#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;
|
||||
const rowGroupId = row.dataset.groupId || "";
|
||||
const show = groupId === ""
|
||||
? true
|
||||
: groupId === "none"
|
||||
? rowGroupId === ""
|
||||
: rowGroupId === groupId;
|
||||
row.hidden = !show;
|
||||
}
|
||||
}
|
||||
@@ -102,8 +115,8 @@ export default class ExperiencePhaseDialog extends HandlebarsApplicationMixin(fo
|
||||
+ (parseInt(this.element.querySelector("#collective-discoveries")?.value, 10) || 0)
|
||||
+ (parseInt(this.element.querySelector("#collective-duration")?.value, 10) || 0);
|
||||
|
||||
const groupId = this.element.querySelector("#group-select")?.value || null;
|
||||
if (groupId) {
|
||||
const groupId = this.element.querySelector("#group-select")?.value || "";
|
||||
if (groupId && groupId !== "none") {
|
||||
const group = game.actors.get(groupId);
|
||||
if (group && collective > 0) {
|
||||
const current = group.system?.experience?.dice || 0;
|
||||
@@ -121,8 +134,11 @@ export default class ExperiencePhaseDialog extends HandlebarsApplicationMixin(fo
|
||||
|
||||
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;
|
||||
// Filtre par groupe sélectionné (vide = tous, "none" = sans groupe)
|
||||
const rowGroupId = row.dataset.groupId || "";
|
||||
if (groupId === "none" ? rowGroupId !== "" : groupId !== "" && rowGroupId !== groupId) continue;
|
||||
// Case « Inclure » décochée → personnage exclu de cette phase
|
||||
if (!row.querySelector(`[name="include-${row.dataset.characterId}"]`)?.checked) continue;
|
||||
const id = row.dataset.characterId;
|
||||
const actor = game.actors.get(id);
|
||||
if (!actor) continue;
|
||||
@@ -164,7 +180,7 @@ export default class ExperiencePhaseDialog extends HandlebarsApplicationMixin(fo
|
||||
}
|
||||
|
||||
const lines = [`${game.i18n.localize("VERMINE.experience_phase")} +1`];
|
||||
if (groupId) {
|
||||
if (groupId && groupId !== "none") {
|
||||
const group = game.actors.get(groupId);
|
||||
lines.push(`${group?.name ?? ""} (${game.i18n.localize("VERMINE.collective")}): +${collective}D`);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<label class="label" for="evolution-level">{{ localize 'VERMINE.evolution_level' }}</label>
|
||||
<select class="info-value" data-roll="true" id="evolution-level" name="evolution-level">
|
||||
{{#each levels}}
|
||||
<option value="{{ this.value }}">{{ this.value }}D — {{ this.cost }}D</option>
|
||||
<option value="{{ this.value }}">{{ this.value }}D</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
<div class="flexrow bonus-item">
|
||||
<label class="label" for="group-select">{{ localize 'VERMINE.collective_group' }}</label>
|
||||
<select class="info-value" id="group-select" name="group-select">
|
||||
<option value="">{{ localize 'VERMINE.none' }}</option>
|
||||
<option value="">{{ localize 'VERMINE.all_characters' }}</option>
|
||||
<option value="none">{{ localize 'VERMINE.no_group' }}</option>
|
||||
{{#each groups}}
|
||||
<option value="{{ this.id }}">{{ this.name }} ({{ this.dice }}D)</option>
|
||||
{{/each}}
|
||||
@@ -49,8 +50,14 @@
|
||||
{{#each characters}}
|
||||
<details class="difficulty-section" data-character-id="{{ this.id }}" data-group-id="{{ this.groupId }}" open>
|
||||
<summary class="flexrow">
|
||||
<label class="flexrow exp-include-label" title="{{ localize 'VERMINE.include_in_phase' }}">
|
||||
<input type="checkbox" data-roll="true" id="include-{{ this.id }}" name="include-{{ this.id }}" checked />
|
||||
</label>
|
||||
<span class="label">{{ this.name }}</span>
|
||||
<span class="current-values">{{ localize 'VERMINE.experience_dice' }}: {{ this.dice }}D</span>
|
||||
<span class="current-values">
|
||||
{{#if this.groupName}}[{{ this.groupName }}]{{ else }}[{{ localize 'VERMINE.no_group' }}]{{/if}}
|
||||
{{ localize 'VERMINE.experience_dice' }}: {{ this.dice }}D
|
||||
</span>
|
||||
</summary>
|
||||
<div class="flexrow difficulty-controls">
|
||||
<div class="flexcol">
|
||||
|
||||
Reference in New Issue
Block a user