forked from public/foundryvtt-wh4-lang-fr-fr
fix: correction des tests de Corruption pour la locale FR
- Remplacement des comparaisons localisées dans handleCorruptionResult par des chaînes anglaises en dur pour que les paliers de Corruption soient correctement appliqués - Correction de _onResist pour accepter les valeurs anglaises et françaises de sévérité de Corruption - Correction des liens @Corruption[modérée] → @Corruption[moderate] dans les scripts d'effets - Élargissement de la clause de garde dans xS2su09zcza9du09.js pour couvrir les valeurs anglaises et françaises - Ajout de AGENTS.md
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
# AGENTS.md — foundryvtt-wh4-lang-fr-fr
|
||||
|
||||
FoundryVTT WFRP4e French translation module (wh4-fr-translation).
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
npm run build # packs scripts/*.js → modules/loadScripts.js (do NOT edit loadScripts.js manually)
|
||||
python3 -mjson.tool fr.json > /dev/null # validate JSON (CI check)
|
||||
python3 -mjson.tool module.json > /dev/null
|
||||
```
|
||||
|
||||
No test framework exists. Only automated check is JSON validity (`.gitea/workflows/validate.yaml` on every push).
|
||||
|
||||
## Architecture
|
||||
|
||||
- **`fr.json`** (2715 keys) — UI/system flat key→val translations (`WFRP4E.*` namespace)
|
||||
- **`compendium/*.json`** — compendium translations named `{source-module}.{pack-type}.json`; entries keyed by English `id`
|
||||
- **`scripts/*.js`** — ActiveEffect scripts named by Foundry item IDs (GUID-like `a7v422EZcOUUC20X.js`)
|
||||
- **`modules/loadScripts.js`** — **generated** by `npm run build`; never edit directly
|
||||
- **`modules/babele-register.js`** — registers all compendium JSONs with Babele at `init` hook; contains all converter logic
|
||||
- **`modules/addon-register.js`** — patches `game.wfrp4e.config.*` with French strings at `init`/`ready`
|
||||
- **`modules/config-patch.js`** — `WH4FRPatchConfig` class (skill list translation, talent list, NPC details)
|
||||
- **`modules/import-stat-2.js`** — French stat block parser (replaces WFRP4e default)
|
||||
- **`wh4_fr.js`** — entry point, inits `travelv2` and `inn` submodules from `modules/`
|
||||
- **`packs/`** — custom French compendium packs (LevelDB format)
|
||||
- **`patch-styles.css`** — CSS patches
|
||||
|
||||
## Critical conventions
|
||||
|
||||
- **Never use French words as JS variable names** in `scripts/`. `Blessures` and `Tests` shadow WFRP4e internals (the system uses `game.wfrp4e.config.*` lookup based on English names, and `Blessures`/`Tests` as variable names break this). Scan with:
|
||||
```bash
|
||||
node find-blessures-variables.cjs
|
||||
node find-tests-variables.cjs
|
||||
```
|
||||
- Conflicts in the release workflow: `compatibility-verified: '13'` in `.gitea/workflows/release.yaml` but `"verified": "14"` in `module.json`. The CI step overwrites the release yaml's value — but if adding module.json updates, match both.
|
||||
|
||||
## Upstream sync workflow
|
||||
|
||||
When updating to a new WFRP4e release:
|
||||
|
||||
```bash
|
||||
node tools/copy-new-scripts.js --list # count new scripts
|
||||
node tools/copy-new-scripts.js --dry-run # preview
|
||||
node tools/copy-new-scripts.js --copy # copy new scripts
|
||||
node tools/sync-scripts.js # compare scripts with upstream
|
||||
node tools/translate-scripts.js # apply auto-translation passes
|
||||
node tools/check-tests.js # scan for "Tests" in scripts/ content
|
||||
```
|
||||
|
||||
## Release
|
||||
|
||||
Published via Gitea release. The zip includes: `module.json`, `fr.json`, `wh4_fr.js`, `patch-styles.css`, `README.md`, `LICENSE`, `compendium/`, `modules/`, `packs/`, `icons/`, `images/`, `trade/`.
|
||||
|
||||
Detailed architecture reference in `.github/copilot-instructions.md`.
|
||||
@@ -478,6 +478,79 @@ Hooks.on('ready', () => {
|
||||
"doom": "Maudit (-40)"
|
||||
}
|
||||
|
||||
// Patch handleCorruptionResult to use hardcoded English severity comparisons.
|
||||
// The system compares this.options.corruption against game.i18n.localize() values,
|
||||
// which works in English by coincidence ("minor" === "minor") but breaks in French
|
||||
// ("minor" !== "mineur"). Since corruption severity strings ("minor"/"moderate"/"major")
|
||||
// are internal API constants, not user-facing text, we use hardcoded comparisons.
|
||||
const TestWFRP = game.wfrp4e.rolls.TestWFRP;
|
||||
if (TestWFRP?.prototype?.handleCorruptionResult) {
|
||||
TestWFRP.prototype.handleCorruptionResult = async function () {
|
||||
const strength = this.options.corruption;
|
||||
const failed = this.failed;
|
||||
let corruption = 0;
|
||||
switch (strength) {
|
||||
case "minor":
|
||||
if (failed) corruption++;
|
||||
break;
|
||||
case "moderate":
|
||||
if (failed) corruption += 2;
|
||||
else if (this.result.SL < 2) corruption += 1;
|
||||
break;
|
||||
case "major":
|
||||
if (failed) corruption += 3;
|
||||
else if (this.result.SL < 2) corruption += 2;
|
||||
else if (this.result.SL < 4) corruption += 1;
|
||||
break;
|
||||
}
|
||||
if (this.context.reroll || this.context.fortuneUsedAddSL) {
|
||||
const prevFailed = this.context.previousResult.outcome === "failure";
|
||||
switch (strength) {
|
||||
case "minor":
|
||||
if (prevFailed) corruption--;
|
||||
break;
|
||||
case "moderate":
|
||||
if (prevFailed) corruption -= 2;
|
||||
else if (this.context.previousResult.SL < 2) corruption -= 1;
|
||||
break;
|
||||
case "major":
|
||||
if (prevFailed) corruption -= 3;
|
||||
else if (this.context.previousResult.SL < 2) corruption -= 2;
|
||||
else if (this.context.previousResult.SL < 4) corruption -= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
let newCorruption = Number(this.actor.system.status.corruption.value) + corruption;
|
||||
if (newCorruption < 0) newCorruption = 0;
|
||||
if (!this.context.reroll && !this.context.fortuneUsedAddSL)
|
||||
ChatMessage.create(game.wfrp4e.utility.chatDataSetup(game.i18n.format("CHAT.CorruptionFail", { name: this.actor.name, number: corruption }), "gmroll", false));
|
||||
else
|
||||
ChatMessage.create(game.wfrp4e.utility.chatDataSetup(game.i18n.format("CHAT.CorruptionReroll", { name: this.actor.name, number: corruption }), "gmroll", false));
|
||||
await this.actor.update({ "system.status.corruption.value": newCorruption });
|
||||
};
|
||||
}
|
||||
|
||||
// Patch _onResist to accept both raw English and localized French corruption severity.
|
||||
// The original validation compares `this.strength` against localized CORRUPTION.* keys,
|
||||
// which fails when the stored strength is an English API value like "minor" vs French "Mineur".
|
||||
const CorruptionMsgModel = CONFIG.ChatMessage.dataModels?.["corruption"];
|
||||
if (CorruptionMsgModel?._onResist) {
|
||||
CorruptionMsgModel._onResist = async function (ev, target) {
|
||||
const strength = this.strength.toLowerCase();
|
||||
const sMap = {
|
||||
"minor": "minor", "moderate": "moderate", "major": "major",
|
||||
[game.i18n.localize("CORRUPTION.Minor").toLowerCase()]: "minor",
|
||||
[game.i18n.localize("CORRUPTION.Moderate").toLowerCase()]: "moderate",
|
||||
[game.i18n.localize("CORRUPTION.Major").toLowerCase()]: "major",
|
||||
};
|
||||
const normalized = sMap[strength];
|
||||
if (!normalized) return ui.notifications.error("ErrorCorruption", { localize: true });
|
||||
const actors = warhammer.utility.targetedOrAssignedActors();
|
||||
if (!actors.length) return ui.notifications.error("ErrorCharAssigned", { localize: true });
|
||||
actors.forEach(a => a.corruptionDialog(normalized, this.skill));
|
||||
};
|
||||
}
|
||||
|
||||
if (game.user.isGM) {
|
||||
game.wfrp4e.warnDialog.render(true, { focus: true, left: 20, top: 20 });
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -3,7 +3,7 @@
|
||||
if (args.equipped) {
|
||||
this.actor.createEmbeddedDocuments("ActiveEffect", [this.item.effects.contents[1]?.convertToApplied()])
|
||||
this.script.message(`${this.actor.name} porte le <strong>${this.item.name}</strong>. <br>
|
||||
Ils gagnent +1 point de Corruption si un Test d'exposition échoue, ce qui devra être appliqué manuellement.<br> S'ils portent le masque pendant plus d'une heure ou bénéficient de l'un de ses effets, ils sont exposés à @Corruption[modérée]{Corruption Modérée}
|
||||
Ils gagnent +1 point de Corruption si un Test d'exposition échoue, ce qui devra être appliqué manuellement.<br> S'ils portent le masque pendant plus d'une heure ou bénéficient de l'un de ses effets, ils sont exposés à @Corruption[moderate]{Corruption Modérée}
|
||||
`,
|
||||
{whisper: ChatMessage.getWhisperRecipients("GM")})
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ if (args.equipped) {
|
||||
this.actor.createEmbeddedDocuments("ActiveEffect", [this.item.effects.contents[1]?.convertToApplied()])
|
||||
this.script.message(`${this.actor.name} porte le <strong>${this.item.name}</strong>. <br>
|
||||
Ils ne peuvent pas lancer de sorts ni prier pour des Bénédictions et des Miracles.<br>
|
||||
S'ils portent le masque pendant plus d'une heure ou bénéficient de l'un de ses effets, ils sont exposés à @Corruption[modérée]{Corruption modérée}.
|
||||
S'ils portent le masque pendant plus d'une heure ou bénéficient de l'un de ses effets, ils sont exposés à @Corruption[moderate]{Corruption modérée}.
|
||||
`,
|
||||
{whisper: ChatMessage.getWhisperRecipients("GM")})
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
if ([game.i18n.localize("CORRUPTION.Minor"), game.i18n.localize("CORRUPTION.Moderate"), game.i18n.localize("CORRUPTION.Major")].includes(this.item.system.specification.value))
|
||||
if (["minor", "moderate", "major", "Minor", "Moderate", "Major", game.i18n.localize("CORRUPTION.Minor"), game.i18n.localize("CORRUPTION.Moderate"), game.i18n.localize("CORRUPTION.Major")].includes(this.item.system.specification.value))
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user