feat(traits): tâche 0 + phases 2-4 — automatisation complète des Traits
Tâche 0 : - item.mjs : champ equipped sur items génériques + toggle fiche - nouveau module/system/traits.mjs (helpers partagés : equippedItems, lourdMalus, mobilityHandicap, feticheItem…) Phase 2 — Combat : - Lourd : malus cumulés auto (Vigueur < n) dans le dialogue + pool - Rapide : handicap (n) pré-rempli dans la défense (character + PNJ) + note carte - Rafale : case tir en rafale (+2 difficulté), +n réussites si réussi (bonusOnSuccess) - Portée : portée effective n × Vigueur affichée - Maniable/Mobilité : note de rappel (dialogue + carte) - Incapacitant : bouton « Jet de Santé (n) » sur la carte d'échange - getLabel() : libellés caractéristiques/compétences localisés Phase 3 — Jets d'action : - Ponctuel : annule jusqu'à n Handicaps, consommé au jet (Traits supprimé à 0) - Pratique : outil sélectionné +2D au lieu de +1D - Intimidant : case « Brandit » → -1D Psychologie ou Relance 1D - Malus : champ « Malus temporaires » manuel déduit du pool - Durée : note « n tours » sur la carte de jet d'arme - roll() : transmission effectiveRange/mobilityHandicap/ponctuelUsed/intimidant (corrige l'affichage Portée/Mobilité) Phase 4 — Acteur : - Fétiche : +1D Effort ET Sang-Froid (max dérivé, config corrigé), alerte 2+ fétiches, action « Perdre le fétiche » (-2D, max -1D persistant feticheLoss) - Zone : note + bouton « Appliquer aux cibles de la zone » (#onApplyZone) CSS : styles LESS pour les nouvelles classes (fetiche-block, exchange-reminder/zone, traits-reminder, tool-bonus/ponctuel, duree-note) i18n : 29 clés fr/en TRAITS_PLAN.md : plan complet cochée
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { VermineUtils } from "../roll.mjs";
|
||||
import { VermineExchange } from "../exchange.mjs";
|
||||
import { VermineTraits } from "../traits.mjs";
|
||||
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api;
|
||||
|
||||
@@ -56,6 +57,11 @@ export default class CombatDialog extends HandlebarsApplicationMixin(foundry.app
|
||||
this.skillReroll = this.skillValue ? (CONFIG.VERMINE.SkillLevels?.[this.skillValue]?.reroll || 0) : 0;
|
||||
this.basePool = VermineExchange.baseAttackPool(this.actor, this.weapon, this.mode);
|
||||
this.baseDamage = VermineExchange.baseDamage(this.actor, this.weapon);
|
||||
this.rafaleValue = this.mode === "ranged" ? VermineTraits.traitValue(this.weapon, "rafale") : 0;
|
||||
this.rapideHandicap = VermineTraits.traitValue(this.weapon, "rapide");
|
||||
this.zoneValue = VermineTraits.traitValue(this.weapon, "zone");
|
||||
const portee = VermineTraits.traitValue(this.weapon, "portee");
|
||||
this.effectiveRange = this.mode === "ranged" && portee > 0 ? portee * VermineTraits.vigor(this.actor) : null;
|
||||
}
|
||||
|
||||
get title() {
|
||||
@@ -147,7 +153,12 @@ export default class CombatDialog extends HandlebarsApplicationMixin(foundry.app
|
||||
hasAmmo: this.mode === "ranged" && (this.weapon?.system?.ammo ?? 0) > 0,
|
||||
availableSpecialties: actor.items.filter(i => i.type === "specialty"),
|
||||
availableItems: actor.items.filter(i => i.type === "item"),
|
||||
targets
|
||||
targets,
|
||||
lourdMalus: VermineTraits.lourdMalus(actor),
|
||||
mobilityNote: VermineTraits.mobilityNote(actor),
|
||||
hasRafale: this.rafaleValue > 0,
|
||||
rafaleValue: this.rafaleValue,
|
||||
effectiveRange: this.effectiveRange
|
||||
};
|
||||
}
|
||||
|
||||
@@ -167,6 +178,7 @@ export default class CombatDialog extends HandlebarsApplicationMixin(foundry.app
|
||||
|
||||
this.element.querySelector("#second-action")?.addEventListener("change", () => this.#updateUI());
|
||||
this.element.querySelector("#handicap")?.addEventListener("change", () => this.#updateUI());
|
||||
this.element.querySelector("#rafale")?.addEventListener("change", () => this.#updateUI());
|
||||
this.element.querySelector("#human-totem")?.addEventListener("change", () => this.#updateUI());
|
||||
this.element.querySelector("#adapted-totem")?.addEventListener("change", () => this.#updateUI());
|
||||
this.element.querySelector("#pools-spent")?.addEventListener("change", () => this.#updateUI());
|
||||
@@ -210,6 +222,10 @@ export default class CombatDialog extends HandlebarsApplicationMixin(foundry.app
|
||||
return this.#el.querySelector("#use-ammo")?.checked ?? false;
|
||||
}
|
||||
|
||||
#getRafale() {
|
||||
return this.#el.querySelector("#rafale")?.checked ?? false;
|
||||
}
|
||||
|
||||
#getTotems() {
|
||||
return {
|
||||
human: this.#el.querySelector("#human-totem")?.checked ?? false,
|
||||
@@ -222,7 +238,7 @@ export default class CombatDialog extends HandlebarsApplicationMixin(foundry.app
|
||||
}
|
||||
|
||||
getDifficultySelect() {
|
||||
return this.#getDifficultyBase() + (this.#getSecondAction() ? 2 : 0);
|
||||
return this.#getDifficultyBase() + (this.#getSecondAction() ? 2 : 0) + (this.#getRafale() ? 2 : 0);
|
||||
}
|
||||
|
||||
getSkillCategory() {
|
||||
@@ -260,9 +276,11 @@ export default class CombatDialog extends HandlebarsApplicationMixin(foundry.app
|
||||
const toolsChecked = this.#el.querySelector("input[name='usingTools']:checked");
|
||||
const tooling = toolsChecked && toolsChecked.value !== "0" ? 1 : 0;
|
||||
const group = parseInt(this.#el.querySelector("#group")?.value, 10) || 0;
|
||||
const malus = VermineExchange.woundMalus(this.actor);
|
||||
const wound = VermineExchange.woundMalus(this.actor);
|
||||
const lourd = VermineTraits.lourdMalus(this.actor);
|
||||
const malus = wound + lourd;
|
||||
const total = Math.max(0, this.basePool + selfControl + pools + specialty + help + tooling + group - malus);
|
||||
return { ability, skill, selfControl, pools, specialty, help, tooling, group, malus, total };
|
||||
return { ability, skill, selfControl, pools, specialty, help, tooling, group, wound, lourd, malus, total };
|
||||
}
|
||||
|
||||
getDicePool() {
|
||||
@@ -365,9 +383,13 @@ export default class CombatDialog extends HandlebarsApplicationMixin(foundry.app
|
||||
targets,
|
||||
weapon: this.weapon
|
||||
? { name: this.weapon.name, img: this.weapon.img, damage: foundry.utils.duplicate(this.weapon.system.damage) }
|
||||
: null
|
||||
: null,
|
||||
rapideHandicap: this.rapideHandicap || null,
|
||||
zoneValue: this.zoneValue || null
|
||||
};
|
||||
|
||||
const rafale = this.#getRafale();
|
||||
|
||||
const rollParams = {
|
||||
actor: this.actor,
|
||||
NoD: this.getDicePool(),
|
||||
@@ -389,6 +411,13 @@ export default class CombatDialog extends HandlebarsApplicationMixin(foundry.app
|
||||
attack,
|
||||
messageFlags: { "vermine-exchange": attack }
|
||||
};
|
||||
if (rafale && this.rafaleValue > 0) {
|
||||
rollParams.bonusSuccesses = this.rafaleValue;
|
||||
rollParams.bonusOnSuccess = true;
|
||||
}
|
||||
if (this.effectiveRange !== null) rollParams.effectiveRange = this.effectiveRange;
|
||||
const mobilityHandicap = VermineTraits.mobilityHandicap(this.actor);
|
||||
if (mobilityHandicap > 0) rollParams.mobilityHandicap = mobilityHandicap;
|
||||
|
||||
// Fermeture immédiate du dialogue : le jet (et l'animation 3D) continue
|
||||
// en arrière-plan sans bloquer la fermeture.
|
||||
|
||||
Reference in New Issue
Block a user