Compare commits

...

6 Commits

Author SHA1 Message Date
8862698262 Nombreuses corections de scripts...
All checks were successful
Validation JSON / validate (push) Successful in 15s
Release Creation / build (release) Successful in 57s
2026-03-07 15:02:18 +01:00
047933a610 Cleanup old gitlab files
All checks were successful
Validation JSON / validate (push) Successful in 18s
Release Creation / build (release) Successful in 50s
2026-03-07 13:29:29 +01:00
b489f65618 Corrections sur la commande /trade et synchronisation des traductions manquantes 2026-03-07 13:29:09 +01:00
406a535c76 Corrections sur la commande /trade et synchronisation des traductions manquantes 2026-03-07 09:34:41 +01:00
5bc6d0d2f5 Corrections sur les scripts avec wounds/blessures 2026-03-05 20:44:48 +01:00
d557fac83f Corrections sur Sens Aiguisé 2026-03-04 11:46:29 +01:00
92 changed files with 6687 additions and 2303 deletions

View File

@@ -0,0 +1,89 @@
name: Release Creation
on:
release:
types: [published]
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "💡 The ${{ gitea.repository }} repository will be cloned to the runner."
- uses: RouxAntoine/checkout@v3.5.4
# Valider les JSON avant de packager
- name: Valider fr.json et module.json
run: |
python3 -mjson.tool fr.json > /dev/null
python3 -mjson.tool module.json > /dev/null
# Générer modules/loadScripts.js depuis scripts/
- name: Build (génération de loadScripts.js)
run: node scriptPacker.js
# Extraire le numéro de version depuis le tag (sans le 'v' initial)
- name: Extraire la version depuis le tag
id: get_version
uses: battila7/get-version-action@v2
# Mettre à jour version, url, manifest et download dans module.json
- name: Substituer les URLs de Manifest et Download
id: sub_manifest_link_version
uses: microsoft/variable-substitution@v1
with:
files: 'module.json'
env:
version: ${{ steps.get_version.outputs.version-without-v }}
url: https://www.uberwald.me/gitea/${{ gitea.repository }}
manifest: https://www.uberwald.me/gitea/public/foundryvtt-wh4-lang-fr-fr/releases/download/latest/module.json
download: https://www.uberwald.me/gitea/${{ gitea.repository }}/releases/download/${{ github.event.release.tag_name }}/foundryvtt-wh4-lang-fr-fr.zip
# Créer le zip avec uniquement les fichiers nécessaires au module Foundry
- name: Installer zip
run: |
apt update -y
apt install -y zip
- name: Créer l'archive foundryvtt-wh4-lang-fr-fr.zip
run: >
zip -r ./foundryvtt-wh4-lang-fr-fr.zip
module.json
fr.json
wh4_fr.js
patch-styles.css
README.md
LICENSE
compendium/
modules/
packs/
icons/
images/
trade/
# Publier le zip et le module.json sur la release Gitea
- name: setup go
uses: https://github.com/actions/setup-go@v4
with:
go-version: '>=1.20.1'
- name: Publier les assets sur la release Gitea
id: use-go-action
uses: https://gitea.com/actions/release-action@main
with:
files: |-
./foundryvtt-wh4-lang-fr-fr.zip
module.json
api_key: '${{ secrets.ALLOW_PUSH_RELEASE }}'
# Déclarer la release sur le portail FoundryVTT
- name: Publier sur FoundryVTT
uses: https://github.com/djlechuck/foundryvtt-publish-package-action@v1
with:
token: ${{ secrets.FOUNDRYVTT_RELEASE_TOKEN }}
id: 'wh4-fr-translation'
version: ${{ github.event.release.tag_name }}
manifest: 'https://www.uberwald.me/gitea/public/foundryvtt-wh4-lang-fr-fr/releases/download/latest/module.json'
notes: 'https://www.uberwald.me/gitea/${{ gitea.repository }}/releases/tag/${{ github.event.release.tag_name }}'
compatibility-minimum: '13'
compatibility-verified: '13'

View File

@@ -0,0 +1,19 @@
name: Validation JSON
on:
push:
branches:
- '**'
pull_request:
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: RouxAntoine/checkout@v3.5.4
- name: Valider fr.json
run: python3 -mjson.tool fr.json > /dev/null
- name: Valider module.json
run: python3 -mjson.tool module.json > /dev/null

View File

@@ -1,29 +0,0 @@
image: python:3-alpine
before_script:
- apk update
- apk add zip
stages:
- test
- build
test:
stage: test
script:
- python -mjson.tool 'fr.json' > /dev/null
- python -mjson.tool 'module.json' > /dev/null
build:
stage: build
script:
- zip wh4-fr-FR.zip -r *.js *.json *.md compendium lang tables -x ".*"
artifacts:
name: wh4-fr-FR
when: on_success
paths:
- wh4-fr-FR.zip
when: on_success
only:
- tags
- master

View File

@@ -0,0 +1,92 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
// Patterns pour détecter les variables JavaScript nommées "Blessures"
const patterns = [
// Déclarations de variables
/\b(let|const|var)\s+Blessures\b/g,
// Paramètres de fonction
/function\s+\w*\s*\([^)]*\bBlessures\b[^)]*\)/g,
// Arrow functions avec paramètres
/\(\s*[^)]*\bBlessures\b[^)]*\)\s*=>/g,
// Arrow function avec un seul paramètre sans parenthèses
/\bBlessures\s*=>/g,
// Destructuration d'objets
/\{\s*[^}]*\bBlessures\b[^}]*\}\s*=/g,
// Destructuration de tableaux
/\[\s*[^\]]*\bBlessures\b[^\]]*\]\s*=/g,
// Catch clause
/catch\s*\(\s*Blessures\s*\)/g,
// For...of/in loops
/for\s*\(\s*(let|const|var)?\s*Blessures\s+(of|in)\b/g,
];
function findBlessuresInFile(filePath) {
const content = fs.readFileSync(filePath, 'utf-8');
const lines = content.split('\n');
const results = [];
lines.forEach((line, index) => {
patterns.forEach(pattern => {
pattern.lastIndex = 0; // Reset regex
if (pattern.test(line)) {
results.push({
line: index + 1,
content: line.trim()
});
}
});
});
return results;
}
function walkDirectory(dir) {
const files = fs.readdirSync(dir);
const allResults = {};
files.forEach(file => {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
Object.assign(allResults, walkDirectory(filePath));
} else if (file.endsWith('.js')) {
const results = findBlessuresInFile(filePath);
if (results.length > 0) {
allResults[filePath] = results;
}
}
});
return allResults;
}
// Main
const scriptsDir = path.join(__dirname, 'scripts');
console.log('🔍 Recherche des variables JavaScript nommées "Blessures" dans le répertoire scripts/...\n');
if (!fs.existsSync(scriptsDir)) {
console.error('❌ Le répertoire scripts/ n\'existe pas');
process.exit(1);
}
const results = walkDirectory(scriptsDir);
if (Object.keys(results).length === 0) {
console.log('✅ Aucune variable JavaScript nommée "Blessures" trouvée.');
} else {
console.log(`⚠️ ${Object.keys(results).length} fichier(s) contenant des variables "Blessures" :\n`);
Object.entries(results).forEach(([filePath, occurrences]) => {
const relativePath = path.relative(__dirname, filePath);
console.log(`📄 ${relativePath}`);
occurrences.forEach(({ line, content }) => {
console.log(` Ligne ${line}: ${content}`);
});
console.log('');
});
}

92
find-tests-variables.cjs Normal file
View File

@@ -0,0 +1,92 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
// Patterns pour détecter les variables JavaScript nommées "Tests"
const patterns = [
// Déclarations de variables
/\b(let|const|var)\s+Tests\b/g,
// Paramètres de fonction
/function\s+\w*\s*\([^)]*\bTests\b[^)]*\)/g,
// Arrow functions avec paramètres
/\(\s*[^)]*\bTests\b[^)]*\)\s*=>/g,
// Arrow function avec un seul paramètre sans parenthèses
/\bTests\s*=>/g,
// Destructuration d'objets
/\{\s*[^}]*\bTests\b[^}]*\}\s*=/g,
// Destructuration de tableaux
/\[\s*[^\]]*\bTests\b[^\]]*\]\s*=/g,
// Catch clause
/catch\s*\(\s*Tests\s*\)/g,
// For...of/in loops
/for\s*\(\s*(let|const|var)?\s*Tests\s+(of|in)\b/g,
];
function findTestsInFile(filePath) {
const content = fs.readFileSync(filePath, 'utf-8');
const lines = content.split('\n');
const results = [];
lines.forEach((line, index) => {
patterns.forEach(pattern => {
pattern.lastIndex = 0; // Reset regex
if (pattern.test(line)) {
results.push({
line: index + 1,
content: line.trim()
});
}
});
});
return results;
}
function walkDirectory(dir) {
const files = fs.readdirSync(dir);
const allResults = {};
files.forEach(file => {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
Object.assign(allResults, walkDirectory(filePath));
} else if (file.endsWith('.js')) {
const results = findTestsInFile(filePath);
if (results.length > 0) {
allResults[filePath] = results;
}
}
});
return allResults;
}
// Main
const scriptsDir = path.join(__dirname, 'scripts');
console.log('🔍 Recherche des variables JavaScript nommées "Tests" dans le répertoire scripts/...\n');
if (!fs.existsSync(scriptsDir)) {
console.error('❌ Le répertoire scripts/ n\'existe pas');
process.exit(1);
}
const results = walkDirectory(scriptsDir);
if (Object.keys(results).length === 0) {
console.log('✅ Aucune variable JavaScript nommée "Tests" trouvée.');
} else {
console.log(`⚠️ ${Object.keys(results).length} fichier(s) contenant des variables "Tests" :\n`);
Object.entries(results).forEach(([filePath, occurrences]) => {
const relativePath = path.relative(__dirname, filePath);
console.log(`📄 ${relativePath}`);
occurrences.forEach(({ line, content }) => {
console.log(` Ligne ${line}: ${content}`);
});
console.log('');
});
}

4057
fr.json

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@
}
],
"url": "https://www.uberwald.me/gitea/public/foundryvtt-wh4-lang-fr-fr",
"version": "9.4.1",
"version": "9.4.3",
"esmodules": [
"wh4_fr.js",
"modules/babele-register.js",
@@ -119,8 +119,8 @@
"folders": []
}
],
"manifest": "https://www.uberwald.me/gitea/public/foundryvtt-wh4-lang-fr-fr/raw/v10/module.json",
"download": "https://www.uberwald.me/gitea/public/foundryvtt-wh4-lang-fr-fr/archive/foundryvtt-wh4-lang-fr-9-4-1.zip",
"manifest": "https://www.uberwald.me/gitea/public/foundryvtt-wh4-lang-fr-fr/releases/download/latest/module.json",
"download": "https://www.uberwald.me/gitea/public/foundryvtt-wh4-lang-fr-fr/releases/download/latest/foundryvtt-wh4-lang-fr-fr.zip",
"id": "wh4-fr-translation",
"compatibility": {
"minimum": "13",

View File

@@ -133,10 +133,10 @@ const __auto_patch_translation_journal_compendium = async (compmod) => {
if (game.user.isGM) {
let compData = game.packs.get("WH4-fr-translation.tables-des-traductions");
compData.locked = false;
let translEntries = await compData.getContent();
let translEntries = await compData.getDocuments();
for (let entryData of translEntries) {
let mydata = foundry.utils.duplicate(entryData.data);
mydata.content = mydata.content.replace(/wfrp4e-content/g, compmod);
let mydata = entryData.toObject();
mydata.text.content = mydata.text.content.replace(/wfrp4e-content/g, compmod);
entryData.update(mydata);
}
compData.locked = true;
@@ -175,9 +175,55 @@ const patch_core_tables = (tableList) => {
/************************************************************************************/
const patch_trade_gazeteer = () => {
if (game.wfrp4e.config.trade?.gazetteer) {
// Translate river cargoTypes to French (DotR module registers English values)
if (game.wfrp4e.trade?.tradeData?.river?.cargoTypes) {
Object.assign(game.wfrp4e.trade.tradeData.river.cargoTypes, {
"grain": game.i18n.localize("TRADE.Grain"),
"armaments": game.i18n.localize("TRADE.Armaments"),
"luxuries": game.i18n.localize("TRADE.Luxuries"),
"metal": game.i18n.localize("TRADE.Metal"),
"timber": game.i18n.localize("TRADE.Timber"),
"wine": game.i18n.localize("TRADE.Wine"),
"brandy": game.i18n.localize("TRADE.Brandy"),
"wool": game.i18n.localize("TRADE.Wool"),
});
}
// Translate maritime cargoTypes to French (SOC module)
if (game.wfrp4e.trade?.tradeData?.maritime?.cargoTypes) {
const maritimeKeys = {
"citrusfruit": "TRADE.Citrusfruit",
"olives": "TRADE.Olives",
"saltfish": "TRADE.Saltfish",
"stone": "TRADE.Stone",
};
for (let [key, locKey] of Object.entries(maritimeKeys)) {
if (game.wfrp4e.trade.tradeData.maritime.cargoTypes[key]) {
game.wfrp4e.trade.tradeData.maritime.cargoTypes[key] = game.i18n.localize(locKey);
}
}
// Translate shared keys that may also appear in maritime
Object.assign(game.wfrp4e.trade.tradeData.maritime.cargoTypes,
Object.fromEntries(
Object.entries(game.wfrp4e.trade.tradeData.maritime.cargoTypes)
.filter(([k]) => game.wfrp4e.trade.tradeData.river?.cargoTypes?.[k])
.map(([k]) => [k, game.wfrp4e.trade.tradeData.river.cargoTypes[k]])
)
);
}
// Translate season names shown in the trade dialog
if (game.wfrp4e.trade?.seasons) {
Object.assign(game.wfrp4e.trade.seasons, {
"spring": game.i18n.localize("TRADE.Spring"),
"summer": game.i18n.localize("TRADE.Summer"),
"autumn": game.i18n.localize("TRADE.Autumn"),
"winter": game.i18n.localize("TRADE.Winter"),
});
}
// Replace the English DotR gazetteer with the French-translated one
// New API: game.wfrp4e.trade.gazetteers.river (replaces old game.wfrp4e.config.trade.gazetteer)
if (game.wfrp4e.trade?.gazetteers?.river?.length) {
fetch("modules/wh4-fr-translation/trade/gazetteer_dotr.json").then(r => r.json()).then(records => {
game.wfrp4e.config.trade.gazetteer = records;
game.wfrp4e.trade.gazetteers.river = records;
});
}
}

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
MANIFEST-001295
MANIFEST-001311

View File

@@ -1,7 +1,7 @@
2026/02/26-22:04:24.137615 7f63f7fff6c0 Recovering log #1293
2026/02/26-22:04:24.149067 7f63f7fff6c0 Delete type=3 #1291
2026/02/26-22:04:24.149129 7f63f7fff6c0 Delete type=0 #1293
2026/02/26-22:04:46.481770 7f61f6fff6c0 Level-0 table #1298: started
2026/02/26-22:04:46.481795 7f61f6fff6c0 Level-0 table #1298: 0 bytes OK
2026/02/26-22:04:46.488240 7f61f6fff6c0 Delete type=0 #1296
2026/02/26-22:04:46.495528 7f61f6fff6c0 Manual compaction at level-0 from '!journal!3IgmiprzLB6Lwenc' @ 72057594037927935 : 1 .. '!journal.pages!suuYN87Al1ZZWtQQ.jhgNnhWhrkOpKs1B' @ 0 : 0; will stop at (end)
2026/03/07-00:45:53.808506 7fe8c37fe6c0 Recovering log #1309
2026/03/07-00:45:53.819278 7fe8c37fe6c0 Delete type=3 #1307
2026/03/07-00:45:53.819338 7fe8c37fe6c0 Delete type=0 #1309
2026/03/07-01:11:49.557068 7fe8c2ffd6c0 Level-0 table #1314: started
2026/03/07-01:11:49.557102 7fe8c2ffd6c0 Level-0 table #1314: 0 bytes OK
2026/03/07-01:11:49.563625 7fe8c2ffd6c0 Delete type=0 #1312
2026/03/07-01:11:49.577541 7fe8c2ffd6c0 Manual compaction at level-0 from '!journal!3IgmiprzLB6Lwenc' @ 72057594037927935 : 1 .. '!journal.pages!suuYN87Al1ZZWtQQ.jhgNnhWhrkOpKs1B' @ 0 : 0; will stop at (end)

View File

@@ -1,7 +1,7 @@
2026/02/26-22:02:13.939121 7f640dbff6c0 Recovering log #1289
2026/02/26-22:02:13.988348 7f640dbff6c0 Delete type=3 #1287
2026/02/26-22:02:13.988418 7f640dbff6c0 Delete type=0 #1289
2026/02/26-22:03:13.280219 7f61f6fff6c0 Level-0 table #1294: started
2026/02/26-22:03:13.280273 7f61f6fff6c0 Level-0 table #1294: 0 bytes OK
2026/02/26-22:03:13.287523 7f61f6fff6c0 Delete type=0 #1292
2026/02/26-22:03:13.287733 7f61f6fff6c0 Manual compaction at level-0 from '!journal!3IgmiprzLB6Lwenc' @ 72057594037927935 : 1 .. '!journal.pages!suuYN87Al1ZZWtQQ.jhgNnhWhrkOpKs1B' @ 0 : 0; will stop at (end)
2026/03/05-20:38:02.743870 7f7930fff6c0 Recovering log #1305
2026/03/05-20:38:02.754744 7f7930fff6c0 Delete type=3 #1303
2026/03/05-20:38:02.754879 7f7930fff6c0 Delete type=0 #1305
2026/03/05-20:42:36.083534 7f78e15b46c0 Level-0 table #1310: started
2026/03/05-20:42:36.083606 7f78e15b46c0 Level-0 table #1310: 0 bytes OK
2026/03/05-20:42:36.090385 7f78e15b46c0 Delete type=0 #1308
2026/03/05-20:42:36.111635 7f78e15b46c0 Manual compaction at level-0 from '!journal!3IgmiprzLB6Lwenc' @ 72057594037927935 : 1 .. '!journal.pages!suuYN87Al1ZZWtQQ.jhgNnhWhrkOpKs1B' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-001297
MANIFEST-001313

View File

@@ -1,7 +1,7 @@
2026/02/26-22:04:24.151462 7f640d3fe6c0 Recovering log #1295
2026/02/26-22:04:24.164087 7f640d3fe6c0 Delete type=3 #1293
2026/02/26-22:04:24.164148 7f640d3fe6c0 Delete type=0 #1295
2026/02/26-22:04:46.511516 7f61f6fff6c0 Level-0 table #1300: started
2026/02/26-22:04:46.511542 7f61f6fff6c0 Level-0 table #1300: 0 bytes OK
2026/02/26-22:04:46.518083 7f61f6fff6c0 Delete type=0 #1298
2026/02/26-22:04:46.532552 7f61f6fff6c0 Manual compaction at level-0 from '!folders!3uquYH73ttCdoH0I' @ 72057594037927935 : 1 .. '!items!ylFhk7mGZOnAJTUT' @ 0 : 0; will stop at (end)
2026/03/07-00:45:53.822265 7fe9111ff6c0 Recovering log #1311
2026/03/07-00:45:53.832029 7fe9111ff6c0 Delete type=3 #1309
2026/03/07-00:45:53.832089 7fe9111ff6c0 Delete type=0 #1311
2026/03/07-01:11:49.549791 7fe8c2ffd6c0 Level-0 table #1316: started
2026/03/07-01:11:49.549814 7fe8c2ffd6c0 Level-0 table #1316: 0 bytes OK
2026/03/07-01:11:49.556940 7fe8c2ffd6c0 Delete type=0 #1314
2026/03/07-01:11:49.577524 7fe8c2ffd6c0 Manual compaction at level-0 from '!folders!3uquYH73ttCdoH0I' @ 72057594037927935 : 1 .. '!items!ylFhk7mGZOnAJTUT' @ 0 : 0; will stop at (end)

View File

@@ -1,7 +1,7 @@
2026/02/26-22:02:13.990565 7f640d3fe6c0 Recovering log #1291
2026/02/26-22:02:14.041205 7f640d3fe6c0 Delete type=3 #1289
2026/02/26-22:02:14.041341 7f640d3fe6c0 Delete type=0 #1291
2026/02/26-22:03:13.287859 7f61f6fff6c0 Level-0 table #1296: started
2026/02/26-22:03:13.287883 7f61f6fff6c0 Level-0 table #1296: 0 bytes OK
2026/02/26-22:03:13.294100 7f61f6fff6c0 Delete type=0 #1294
2026/02/26-22:03:13.315154 7f61f6fff6c0 Manual compaction at level-0 from '!folders!3uquYH73ttCdoH0I' @ 72057594037927935 : 1 .. '!items!ylFhk7mGZOnAJTUT' @ 0 : 0; will stop at (end)
2026/03/05-20:38:02.758975 7f78e37fe6c0 Recovering log #1307
2026/03/05-20:38:02.770688 7f78e37fe6c0 Delete type=3 #1305
2026/03/05-20:38:02.770801 7f78e37fe6c0 Delete type=0 #1307
2026/03/05-20:42:36.097432 7f78e15b46c0 Level-0 table #1312: started
2026/03/05-20:42:36.097481 7f78e15b46c0 Level-0 table #1312: 0 bytes OK
2026/03/05-20:42:36.104419 7f78e15b46c0 Delete type=0 #1310
2026/03/05-20:42:36.111679 7f78e15b46c0 Manual compaction at level-0 from '!folders!3uquYH73ttCdoH0I' @ 72057594037927935 : 1 .. '!items!ylFhk7mGZOnAJTUT' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-001295
MANIFEST-001311

View File

@@ -1,7 +1,7 @@
2026/02/26-22:04:24.183291 7f640dbff6c0 Recovering log #1293
2026/02/26-22:04:24.198373 7f640dbff6c0 Delete type=3 #1291
2026/02/26-22:04:24.198448 7f640dbff6c0 Delete type=0 #1293
2026/02/26-22:04:46.518228 7f61f6fff6c0 Level-0 table #1298: started
2026/02/26-22:04:46.518251 7f61f6fff6c0 Level-0 table #1298: 0 bytes OK
2026/02/26-22:04:46.524767 7f61f6fff6c0 Delete type=0 #1296
2026/02/26-22:04:46.532566 7f61f6fff6c0 Manual compaction at level-0 from '!journal!cZtNgayIw2QFhC9u' @ 72057594037927935 : 1 .. '!journal.pages!cZtNgayIw2QFhC9u.ts265H1XkisLgdow' @ 0 : 0; will stop at (end)
2026/03/07-00:45:53.847464 7fe8c3fff6c0 Recovering log #1309
2026/03/07-00:45:53.857503 7fe8c3fff6c0 Delete type=3 #1307
2026/03/07-00:45:53.857563 7fe8c3fff6c0 Delete type=0 #1309
2026/03/07-01:11:49.577693 7fe8c2ffd6c0 Level-0 table #1314: started
2026/03/07-01:11:49.577722 7fe8c2ffd6c0 Level-0 table #1314: 0 bytes OK
2026/03/07-01:11:49.583840 7fe8c2ffd6c0 Delete type=0 #1312
2026/03/07-01:11:49.612617 7fe8c2ffd6c0 Manual compaction at level-0 from '!journal!cZtNgayIw2QFhC9u' @ 72057594037927935 : 1 .. '!journal.pages!cZtNgayIw2QFhC9u.ts265H1XkisLgdow' @ 0 : 0; will stop at (end)

View File

@@ -1,7 +1,7 @@
2026/02/26-22:02:14.115468 7f640cbfd6c0 Recovering log #1289
2026/02/26-22:02:14.169882 7f640cbfd6c0 Delete type=3 #1287
2026/02/26-22:02:14.169955 7f640cbfd6c0 Delete type=0 #1289
2026/02/26-22:03:13.301545 7f61f6fff6c0 Level-0 table #1294: started
2026/02/26-22:03:13.301610 7f61f6fff6c0 Level-0 table #1294: 0 bytes OK
2026/02/26-22:03:13.307921 7f61f6fff6c0 Delete type=0 #1292
2026/02/26-22:03:13.315187 7f61f6fff6c0 Manual compaction at level-0 from '!journal!cZtNgayIw2QFhC9u' @ 72057594037927935 : 1 .. '!journal.pages!cZtNgayIw2QFhC9u.ts265H1XkisLgdow' @ 0 : 0; will stop at (end)
2026/03/05-20:38:02.790472 7f78e3fff6c0 Recovering log #1305
2026/03/05-20:38:02.801425 7f78e3fff6c0 Delete type=3 #1303
2026/03/05-20:38:02.801553 7f78e3fff6c0 Delete type=0 #1305
2026/03/05-20:42:36.090593 7f78e15b46c0 Level-0 table #1310: started
2026/03/05-20:42:36.090646 7f78e15b46c0 Level-0 table #1310: 0 bytes OK
2026/03/05-20:42:36.097257 7f78e15b46c0 Delete type=0 #1308
2026/03/05-20:42:36.111659 7f78e15b46c0 Manual compaction at level-0 from '!journal!cZtNgayIw2QFhC9u' @ 72057594037927935 : 1 .. '!journal.pages!cZtNgayIw2QFhC9u.ts265H1XkisLgdow' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-001295
MANIFEST-001311

View File

@@ -1,7 +1,7 @@
2026/02/26-22:04:24.123515 7f640d3fe6c0 Recovering log #1293
2026/02/26-22:04:24.135202 7f640d3fe6c0 Delete type=3 #1291
2026/02/26-22:04:24.135283 7f640d3fe6c0 Delete type=0 #1293
2026/02/26-22:04:46.488408 7f61f6fff6c0 Level-0 table #1298: started
2026/02/26-22:04:46.488442 7f61f6fff6c0 Level-0 table #1298: 0 bytes OK
2026/02/26-22:04:46.495308 7f61f6fff6c0 Delete type=0 #1296
2026/02/26-22:04:46.495540 7f61f6fff6c0 Manual compaction at level-0 from '!journal!50u8VAjdmovyr0hx' @ 72057594037927935 : 1 .. '!journal.pages!yzw9I0r3hCK7PJnz.sPNCYj2nR3Cp3jHd' @ 0 : 0; will stop at (end)
2026/03/07-00:45:53.792556 7fe8c3fff6c0 Recovering log #1309
2026/03/07-00:45:53.805674 7fe8c3fff6c0 Delete type=3 #1307
2026/03/07-00:45:53.805724 7fe8c3fff6c0 Delete type=0 #1309
2026/03/07-01:11:49.563712 7fe8c2ffd6c0 Level-0 table #1314: started
2026/03/07-01:11:49.563733 7fe8c2ffd6c0 Level-0 table #1314: 0 bytes OK
2026/03/07-01:11:49.570212 7fe8c2ffd6c0 Delete type=0 #1312
2026/03/07-01:11:49.577555 7fe8c2ffd6c0 Manual compaction at level-0 from '!journal!50u8VAjdmovyr0hx' @ 72057594037927935 : 1 .. '!journal.pages!yzw9I0r3hCK7PJnz.sPNCYj2nR3Cp3jHd' @ 0 : 0; will stop at (end)

View File

@@ -1,7 +1,7 @@
2026/02/26-22:02:13.889590 7f63f7fff6c0 Recovering log #1289
2026/02/26-22:02:13.936962 7f63f7fff6c0 Delete type=3 #1287
2026/02/26-22:02:13.937017 7f63f7fff6c0 Delete type=0 #1289
2026/02/26-22:03:13.273521 7f61f6fff6c0 Level-0 table #1294: started
2026/02/26-22:03:13.273553 7f61f6fff6c0 Level-0 table #1294: 0 bytes OK
2026/02/26-22:03:13.280005 7f61f6fff6c0 Delete type=0 #1292
2026/02/26-22:03:13.287724 7f61f6fff6c0 Manual compaction at level-0 from '!journal!50u8VAjdmovyr0hx' @ 72057594037927935 : 1 .. '!journal.pages!yzw9I0r3hCK7PJnz.sPNCYj2nR3Cp3jHd' @ 0 : 0; will stop at (end)
2026/03/05-20:38:02.727495 7f78e2ffd6c0 Recovering log #1305
2026/03/05-20:38:02.739900 7f78e2ffd6c0 Delete type=3 #1303
2026/03/05-20:38:02.740017 7f78e2ffd6c0 Delete type=0 #1305
2026/03/05-20:42:36.060514 7f78e15b46c0 Level-0 table #1310: started
2026/03/05-20:42:36.060577 7f78e15b46c0 Level-0 table #1310: 0 bytes OK
2026/03/05-20:42:36.067949 7f78e15b46c0 Delete type=0 #1308
2026/03/05-20:42:36.083144 7f78e15b46c0 Manual compaction at level-0 from '!journal!50u8VAjdmovyr0hx' @ 72057594037927935 : 1 .. '!journal.pages!yzw9I0r3hCK7PJnz.sPNCYj2nR3Cp3jHd' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-001295
MANIFEST-001311

View File

@@ -1,7 +1,7 @@
2026/02/26-22:04:24.106231 7f640dbff6c0 Recovering log #1293
2026/02/26-22:04:24.120853 7f640dbff6c0 Delete type=3 #1291
2026/02/26-22:04:24.120905 7f640dbff6c0 Delete type=0 #1293
2026/02/26-22:04:46.475371 7f61f6fff6c0 Level-0 table #1298: started
2026/02/26-22:04:46.475399 7f61f6fff6c0 Level-0 table #1298: 0 bytes OK
2026/02/26-22:04:46.481643 7f61f6fff6c0 Delete type=0 #1296
2026/02/26-22:04:46.495513 7f61f6fff6c0 Manual compaction at level-0 from '!tables!4l60Lxv8cpsyy2Cg' @ 72057594037927935 : 1 .. '!tables.results!tfaYKDZqu7kgZvRG.yvbwKursaixh2dby' @ 0 : 0; will stop at (end)
2026/03/07-00:45:53.774458 7fe8c37fe6c0 Recovering log #1309
2026/03/07-00:45:53.787633 7fe8c37fe6c0 Delete type=3 #1307
2026/03/07-00:45:53.787702 7fe8c37fe6c0 Delete type=0 #1309
2026/03/07-01:11:49.543331 7fe8c2ffd6c0 Level-0 table #1314: started
2026/03/07-01:11:49.543361 7fe8c2ffd6c0 Level-0 table #1314: 0 bytes OK
2026/03/07-01:11:49.549597 7fe8c2ffd6c0 Delete type=0 #1312
2026/03/07-01:11:49.549676 7fe8c2ffd6c0 Manual compaction at level-0 from '!tables!4l60Lxv8cpsyy2Cg' @ 72057594037927935 : 1 .. '!tables.results!tfaYKDZqu7kgZvRG.yvbwKursaixh2dby' @ 0 : 0; will stop at (end)

View File

@@ -1,7 +1,7 @@
2026/02/26-22:02:13.830812 7f640d3fe6c0 Recovering log #1289
2026/02/26-22:02:13.887231 7f640d3fe6c0 Delete type=3 #1287
2026/02/26-22:02:13.887289 7f640d3fe6c0 Delete type=0 #1289
2026/02/26-22:03:13.266764 7f61f6fff6c0 Level-0 table #1294: started
2026/02/26-22:03:13.266813 7f61f6fff6c0 Level-0 table #1294: 0 bytes OK
2026/02/26-22:03:13.273358 7f61f6fff6c0 Delete type=0 #1292
2026/02/26-22:03:13.287711 7f61f6fff6c0 Manual compaction at level-0 from '!tables!4l60Lxv8cpsyy2Cg' @ 72057594037927935 : 1 .. '!tables.results!tfaYKDZqu7kgZvRG.yvbwKursaixh2dby' @ 0 : 0; will stop at (end)
2026/03/05-20:38:02.710364 7f7930fff6c0 Recovering log #1305
2026/03/05-20:38:02.722794 7f7930fff6c0 Delete type=3 #1303
2026/03/05-20:38:02.722917 7f7930fff6c0 Delete type=0 #1305
2026/03/05-20:42:36.068193 7f78e15b46c0 Level-0 table #1310: started
2026/03/05-20:42:36.068246 7f78e15b46c0 Level-0 table #1310: 0 bytes OK
2026/03/05-20:42:36.074966 7f78e15b46c0 Delete type=0 #1308
2026/03/05-20:42:36.083182 7f78e15b46c0 Manual compaction at level-0 from '!tables!4l60Lxv8cpsyy2Cg' @ 72057594037927935 : 1 .. '!tables.results!tfaYKDZqu7kgZvRG.yvbwKursaixh2dby' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000938
MANIFEST-000954

View File

@@ -1,7 +1,7 @@
2026/02/26-22:04:24.166725 7f63f7fff6c0 Recovering log #936
2026/02/26-22:04:24.181007 7f63f7fff6c0 Delete type=3 #934
2026/02/26-22:04:24.181079 7f63f7fff6c0 Delete type=0 #936
2026/02/26-22:04:46.525121 7f61f6fff6c0 Level-0 table #941: started
2026/02/26-22:04:46.525166 7f61f6fff6c0 Level-0 table #941: 0 bytes OK
2026/02/26-22:04:46.532271 7f61f6fff6c0 Delete type=0 #939
2026/02/26-22:04:46.532577 7f61f6fff6c0 Manual compaction at level-0 from '!journal!056ILNNrLiPq3Gi3' @ 72057594037927935 : 1 .. '!journal.pages!yfZxl4I7XAuUF6r3.apXmOlZRmGT4GreB' @ 0 : 0; will stop at (end)
2026/03/07-00:45:53.835083 7fe8c37fe6c0 Recovering log #952
2026/03/07-00:45:53.844848 7fe8c37fe6c0 Delete type=3 #950
2026/03/07-00:45:53.844893 7fe8c37fe6c0 Delete type=0 #952
2026/03/07-01:11:49.570293 7fe8c2ffd6c0 Level-0 table #957: started
2026/03/07-01:11:49.570316 7fe8c2ffd6c0 Level-0 table #957: 0 bytes OK
2026/03/07-01:11:49.577407 7fe8c2ffd6c0 Delete type=0 #955
2026/03/07-01:11:49.577567 7fe8c2ffd6c0 Manual compaction at level-0 from '!journal!056ILNNrLiPq3Gi3' @ 72057594037927935 : 1 .. '!journal.pages!yfZxl4I7XAuUF6r3.apXmOlZRmGT4GreB' @ 0 : 0; will stop at (end)

View File

@@ -1,7 +1,7 @@
2026/02/26-22:02:14.050871 7f640dbff6c0 Recovering log #932
2026/02/26-22:02:14.109358 7f640dbff6c0 Delete type=3 #930
2026/02/26-22:02:14.109436 7f640dbff6c0 Delete type=0 #932
2026/02/26-22:03:13.308043 7f61f6fff6c0 Level-0 table #937: started
2026/02/26-22:03:13.308070 7f61f6fff6c0 Level-0 table #937: 0 bytes OK
2026/02/26-22:03:13.315010 7f61f6fff6c0 Delete type=0 #935
2026/02/26-22:03:13.315204 7f61f6fff6c0 Manual compaction at level-0 from '!journal!056ILNNrLiPq3Gi3' @ 72057594037927935 : 1 .. '!journal.pages!yfZxl4I7XAuUF6r3.apXmOlZRmGT4GreB' @ 0 : 0; will stop at (end)
2026/03/05-20:38:02.775184 7f7930fff6c0 Recovering log #948
2026/03/05-20:38:02.786747 7f7930fff6c0 Delete type=3 #946
2026/03/05-20:38:02.786856 7f7930fff6c0 Delete type=0 #948
2026/03/05-20:42:36.104620 7f78e15b46c0 Level-0 table #953: started
2026/03/05-20:42:36.104679 7f78e15b46c0 Level-0 table #953: 0 bytes OK
2026/03/05-20:42:36.111433 7f78e15b46c0 Delete type=0 #951
2026/03/05-20:42:36.111701 7f78e15b46c0 Manual compaction at level-0 from '!journal!056ILNNrLiPq3Gi3' @ 72057594037927935 : 1 .. '!journal.pages!yfZxl4I7XAuUF6r3.apXmOlZRmGT4GreB' @ 0 : 0; will stop at (end)

View File

@@ -1,31 +1,28 @@
if (!this.item.name.includes("(") || this.item.system.tests.value.includes("Terrain") || this.item.system.tests.value.toLowerCase().includes("(any)"))
{
let Tests = this.item.system.tests.value
let name = this.item.name
if (!this.item.name.includes("(") || this.item.system.tests.value.includes("Terrain") || this.item.system.tests.value.toLowerCase().includes("(any)")) {
let tests = this.item.system.tests.value
let name = this.item.name
// If name already specifies, make sure Tests value reflects that
if (name.includes("(") && !name.toLowerCase().includes("(any)"))
{
let terrain = name.split("(")[1].split(")")[0]
tests = tests.replace("the Terrain", terrain)
}
else // If no sense specified, provide dialog choice
{
let choice = await ItemDialog.create(ItemDialog.objectToArray({
coastal : "Littoral",
deserts : "Déserts",
marshes : "Marécages",
rocky : "Rocailleux",
tundra : "Toundra",
woodlands : "Régions boisées"
}, this.item.img), 1, "Choisissez un Terrain");
if (choice[0])
{
name = `${name.split("(")[0].trim()} (${choice[0].name})`
tests = tests.replace("Terrain", choice[0].name + " Terrain")
}
// If name already specifies, make sure Tests value reflects that
if (name.includes("(") && !name.toLowerCase().includes("(any)")) {
let terrain = name.split("(")[1].split(")")[0]
tests = tests.replace("the Terrain", terrain)
}
else // If no sense specified, provide dialog choice
{
let choice = await ItemDialog.create(ItemDialog.objectToArray({
coastal: "Littoral",
deserts: "Déserts",
marshes: "Marécages",
rocky: "Rocailleux",
tundra: "Toundra",
woodlands: "Régions boisées"
}, this.item.img), 1, "Choisissez un Terrain");
if (choice[0]) {
name = `${name.split("(")[0].trim()} (${choice[0].name})`
tests = tests.replace("Terrain", choice[0].name + " Terrain")
}
}
this.effect.updateSource({name})
this.item.updateSource({name, "system.tests.value" : tests})
this.effect.updateSource({ name })
this.item.updateSource({ name, "system.tests.value": tests })
}

View File

@@ -14,7 +14,7 @@
let updateObj = this.actor.toObject();
let talents = (await Promise.tout([game.wfrp4e.tables.rollTable("talents"), game.wfrp4e.tables.rollTable("talents"), game.wfrp4e.tables.rollTable("talents")])).map(i => i.text)
let talents = (await Promise.all([game.wfrp4e.tables.rollTable("talents"), game.wfrp4e.tables.rollTable("talents"), game.wfrp4e.tables.rollTable("talents")])).map(i => i.text)
for (let ch in characteristics)
{

View File

@@ -1,6 +1,6 @@
let test = await args.actor.setupCharacteristic("wp", {skipTargets: true, appendTitle : " - " + this.effect.name, context : {failure: "Gain de 1 état Sonné"}})
await Test.roll();
if (Test.Échoué)
await test.roll();
if (test.failed)
{
args.actor.addCondition("stunned")
}

View File

@@ -1,6 +1,6 @@
let test = await this.actor.setupCharacteristic("ag", {skipTargets: true, appendTitle : ` - ${this.effect.name}`});
await Test.roll();
if (Test.Échoué)
await test.roll();
if (test.failed)
{
this.actor.addCondition("bleeding");
}

View File

@@ -10,17 +10,17 @@ scriptData[0].script = `
let chatData = {whisper: ChatMessage.getWhisperRecipients("GM")};
let message = "";
let Blessures = foundry.utils.duplicate(this.actor.status.Blessures);
let wounds = foundry.utils.duplicate(this.actor.status.wounds);
let regenRoll = await new Roll("1d10").roll({allowInteractive : false});
let regen = regenRoll.total;
if (Blessures.value >= Blessures.max)
if (wounds.value >= wounds.max)
return;
if (Blessures.value > 0) {
Blessures.value += Math.floor(regen / 2);
if (Blessures.value > Blessures.max) {
Blessures.value = Blessures.max;
if (wounds.value > 0) {
wounds.value += Math.floor(regen / 2);
if (wounds.value > wounds.max) {
wounds.value = wounds.max;
}
message += \`<b>\${this.actor.name}</b> regagne \${regen} Blessures.\`;
@@ -29,7 +29,7 @@ scriptData[0].script = `
}
} else if (regen >= 8) {
message += \`<b>\${this.actor.name}</b> a obtenu un \${regen} et regagne 1 Blessure.\`;
Blessures.value += 1;
wounds.value += 1;
if (regen === 10) {
message += "<br>De plus, il régénère une Blessure Critique.";
}
@@ -37,7 +37,7 @@ scriptData[0].script = `
message += \`<b>\${this.actor.name}</b> Résultat de régénération de \${regen} - Aucun effet.\`;
}
await this.actor.update({"system.status.wounds": Blessures});
await this.actor.update({"system.status.wounds": wounds});
this.script.message(message, {whisper: ChatMessage.getWhisperRecipients("GM")});
`
@@ -46,4 +46,4 @@ await effet.update({
"system.scriptData": scriptData
});
await trait.update({name});
await trait.update({ name });

View File

@@ -1,6 +1,6 @@
let test = await this.actor.setupCharacteristic("wp", {skipTargets: true, appendTitle : " - " + this.effect.name, context : {failure: "GAin d'1 état Sonné"}})
await Test.roll();
if (Test.Échoué)
await test.roll();
if (test.failed)
{
this.actor.addCondition("stunned");
}

View File

@@ -22,7 +22,7 @@ let Test = await actor.setupSkill('Calme', {
fields: {difficulty: 'easy'},
characteristic: 'wp',
});
await Test.roll();
await test.roll();
if (!Test.succeeded) {
Test.result.other.push(`<b>${actor.name}</b> est devenu @Condition[Stunned] par la vue.`);

View File

@@ -10,12 +10,12 @@ const test = await this.actor.setupSkill(game.i18n.localize("NAME.Résistance"),
}
});
await Test.roll();
await test.roll();
if (Test.Échoué) {
if (test.failed) {
await this.actor.addEffectItems(bloodyFluxUUID, this.effet);
} else {
const SL = Test.result.SL;
const SL = test.result.SL;
const heal = 1 + SL;
await this.actor.modifyWounds(heal);
this.script.message(`Butcher a soigné ${heal} Blessures.`);

View File

@@ -1,12 +1,12 @@
// Imbibing this substance grants the user the utilisateur d Creature Trait.
const hasutilisateur d = this.actor.has("Insensible à la douleur");
if (hasutilisateur d === undefined)
// Imbibing this substance grants the user the Painless Creature Trait.
const hasPainless = this.actor.has("Insensible à la douleur");
if (hasPainless === undefined)
{
let item = await fromUuid("Compendium.wfrp4e-core.items.wMwSRDmgiF2IdCJr");
let data = item.toObject()
this.actor.createEmbeddedDocuments("Item", [data], {fromEffect: this.effect.id})
this.script.message(
this.script.scriptMessage(
`<p><strong>${this.actor.prototypeToken.name}</strong> a acquis le Trait de Créature Insensible à la douleur. Cet
effet dure une heure, après quoi il se dissipe et l'effet complet
de toutes les blessures du buveur s'abat d'un coup.</p>

View File

@@ -7,9 +7,9 @@ const test = await args.actor.setupSkill(game.i18n.localize("NAME.Résistance"),
}
});
await Test.roll();
await test.roll();
if (Test.Échoué) {
if (test.failed) {
args.actor.addCondition("poisoned");
const speaker = ChatMessage.getSpeaker({actor: args.actor});
this.script.message(`<p>${speaker.alias} a reçu 1 état @Condition[Poisoned] de Venin d'Araignée.</p><p>Les victimes réduites à 0 blessures et qui souffrent d'un état @Condition[Poisoned] de ces flèches deviennent @Condition[Unconcious], mais ne risquent pas la mort à cause des états @Condition[Poisoned] restants comme ce serait normalement le cas.</p>`);

View File

@@ -1,7 +1,7 @@
if (args.test.result.SL < 0)
{
this.script.message(`Gain de ${Math.abs(args.test.result.SL)} Points de Corruption`, {whisper : ChatMessage.getWhisperRecipients("GM")})
if (args.Test.Échoué && this.actor.type == "character")
if (args.test.failed && this.actor.type == "character")
{
this.actor.update({"system.status.corruption.value" : parseInt(this.actor.status.corruption.value) + Math.abs(args.test.result.SL)})
}

View File

@@ -13,9 +13,9 @@ let test = await actor.setupCharacteristic("s", {
}
});
await Test.roll();
if (Test.succeeded) {
let SL = parseInt(Test.result.SL);
await test.roll();
if (test.succeeded) {
let SL = parseInt(test.result.SL);
let name = this.effect.name.replace(/\d+/, rating => parseInt(rating) - SL);
await this.effect.update({name});
}

View File

@@ -1,11 +1,11 @@
let test = await this.actor.setupCharacteristic("s", {appendTitle : ` - ${this.effect.name}`, fields : {difficulty : "difficult"}});
await Test.roll();
await test.roll();
if (Test.Échoué)
if (test.failed)
{
if (Test.isCriticalFumble == "fumble")
if (test.isCriticalFumble == "fumble")
{
return this.script.message(`<strong>${this.actor.name}</strong> meurt alors qu'il est entraîné dans l'Aethyr (à moins qu'il ne dépense un point de Destinée pour éviter cela).`);
}

View File

@@ -22,7 +22,7 @@ let Test = await actor.setupSkill('Calme', {
fields: {difficulty: 'easy'},
characteristic: 'wp',
});
await Test.roll();
await test.roll();
if (!Test.succeeded) {
Test.result.other.push(`<b>${actor.name}</b> est devenu fasciné par la vue et incapable d'effectuer une quelconque action autre que de se déplacer vers la lumière.`);

View File

@@ -1,4 +1,4 @@
if (args.test.characteristicKey == "wp" && args.Test.Échoué && args.Test.result.SL <= -3)
if (args.test.characteristicKey == "wp" && args.test.failed && args.test.result.SL <= -3)
{
this.script.notification("Ajout de A Terre");
this.actor.addCondition("prone")

View File

@@ -1,6 +1,6 @@
let test = await this.actor.setupCharacteristic("wp", {skipTargets: true, appendTitle : ` - ${this.effect.name}`})
await Test.roll();
if (Test.succeeded)
await test.roll();
if (test.succeeded)
{
this.script.message("Peut réaliser une Action ou un Déplacement (choisissez-en un)")
}

View File

@@ -1 +1 @@
this.script.scirptMessage(await this.actor.applyBasicDamage(20, {suppressMsg: true});
this.script.scriptMessage(await this.actor.applyBasicDamage(20, {suppressMsg: true}));

View File

@@ -1,7 +1,7 @@
let test = await this.actor.setupSkill(game.i18n.localize("NAME.Dodge"), {fields : {difficulty : "hard"}, appendTitle : ` - ${this.effect.name}`})
await Test.roll();
await test.roll();
if (Test.Échoué) {
if (test.failed) {
this.script.scriptMessage(await this.actor.applyBasicDamage(20, {suppressMsg: true}));
this.script.scriptMessage(`${this.actor.name} est victime de @UUID[Compendium.wfrp4e-core.journals.JournalEntry.NS3YGlJQxwTggjRX.JournalEntryPage.WCivInLZrqEtZzF4#drowning-and-suffocation]{Suffocation}`);
}

View File

@@ -1,6 +1,6 @@
if (args.test.characteristicKey == "wp")
{
if (args.Test.Échoué)
if (args.test.failed)
{
this.actor.addSystemEffect("convulsions")
this.script.message(`Test de FM échoué, <b>${this.actor.prototypeToken.name}</b> reçoit @Symptom[Convulsions] pour [[1d10]] heures`)

View File

@@ -9,7 +9,7 @@ if (god)
{
let prayers = await warhammer.utility.findAllItems("prayer", "Chargement des Prières", true, ["system.type.value", "system.god.value"])
let blessings = prayers.filter(p => p.system.god.value.split(",").map(i => i.trim().toLowerCase()).includes(god.toLowerCase()) && p.system.type.value == "blessing")
let configBlessings = await Promise.tout((game.wfrp4e.config.godBlessings[god.toLowerCase()] || []).map(fromUuid));
let configBlessings = await Promise.all((game.wfrp4e.config.godBlessings[god.toLowerCase()] || []).map(fromUuid));
if (god == "Foi Antique")
{
blessings = await ItemDialog.create(prayers.filter(i => i.system.type.value == "blessing"), 6, {text : "Sélectionnez 6 Bénédictions", title : "Béni"})

View File

@@ -1,6 +1,6 @@
let test = await this.actor.setupCharacteristic("wp", {skipTargets: true, appendTitle : ` - ${this.effect.name}`})
await Test.roll();
if (Test.Échoué)
await test.roll();
if (test.failed)
{
this.script.message(await game.wfrp4e.tables.formatChatRoll("enrage-beast"))
}

View File

@@ -1,7 +1,7 @@
if (this.actor.Species.toLowerCase() != "skaven") {
this.actor.setupCharacteristic("t", {skipTargets: true, appendTitle : ` - Utilise ${this.effect.name}`, fields: { difficulty: "difficult" } }).then(async Test => {
await Test.roll()
if (Test.Échoué)
await test.roll()
if (test.failed)
{
let toughnessLost = Math.ceil(CONFIG.Dice.randomUniform() * 10)
this.actor.update({ "system.characteristics.t.initial": this.actor.characteristics.t.initial - toughnessLost })

View File

@@ -1,7 +1,7 @@
let test = await this.actor.setupCharacteristic("wp", {fields: {difficulty : "average"}, skipTargets: true, appendTitle : ` - ${this.effect.name}`})
await Test.roll();
if (Test.Échoué)
await test.roll();
if (test.failed)
{
let stuns = Math.max(1, Math.abs(Test.result.SL))
let stuns = Math.max(1, Math.abs(test.result.SL))
this.actor.addCondition("stunned", stuns)
}

View File

@@ -5,8 +5,8 @@ if (this.actor.uuid == this.effect.sourceActor.uuid)
if (this.actor.has("À Sang Froid") && !this.actor.hasSystemEffect("nausea")) {
let test = await this.actor.setupSkill(game.i18n.localize("NAME.Résistance"), {appendTitle : `- ${this.effect.name}`})
await Test.roll();
if (Test.Échoué)
await test.roll();
if (test.failed)
{
let myRoll = await new Roll("1d10").roll({allowInteractive : false});

View File

@@ -5,15 +5,15 @@ let wounds = foundry.utils.duplicate(this.actor.status.wounds)
let regenRoll = await new Roll("1d10").roll({allowInteractive : false});
let regen = regenRoll.total;
if (Blessures.value >= Blessures.max)
if (wounds.value >= wounds.max)
return
if (Blessures.value > 0)
if (wounds.value > 0)
{
Blessures.value += regen
if (Blessures.value > Blessures.max)
wounds.value += regen
if (wounds.value > wounds.max)
{
Blessures.value = Blessures.max
wounds.value = wounds.max
}
message += `<b>${this.actor.name}</b> regagne ${regen} Point de Blessures.`
@@ -25,7 +25,7 @@ if (Blessures.value > 0)
else if (regen >= 8)
{
message += `<b>${this.actor.name}</b> a fait un ${regen} et regagne 1 Point de Blessures.`
Blessures.value += 1
wounds.value += 1
if (regen == 10)
{
message += `<br>De plus, il guérit d'une Blessure Critique.`
@@ -36,5 +36,5 @@ else
message += `<b>${this.actor.name}</b> a fait un ${regen} et ne régénère pas de Point de Blessures.`
}
await this.actor.update({ "system.status.wounds": Blessures })
await this.actor.update({ "system.status.wounds": wounds })
this.script.message(message, { whisper: ChatMessage.getWhisperRecipients("GM") })

View File

@@ -1,6 +1,6 @@
let test = await this.actor.setupSkill("Résistance", {fields : {difficulty : "difficult"}, appendTitle : ` - ${this.effect.name}`});
await Test.roll();
if (Test.Échoué)
await test.roll();
if (test.failed)
{
await this.actor.addCondition("blinded");
}

View File

@@ -1,7 +1,7 @@
const test = await this.actor.setupCharacteristic("int", {fields: {difficulty: "easy"}, skipTargets: true, appendTitle : ` - ${this.effect.name}`});
await Test.roll();
await test.roll();
if (Test.Échoué) {
if (test.failed) {
this.actor.addCondition('stunned');
}

View File

@@ -1,6 +1,6 @@
let test = await this.actor.setupCharacteristic("ag", {skipTargets: true, appendTitle : ` - ${this.effect.name}`, context: { failure: "Goes Prone" }})
await Test.roll();
if (Test.Échoué)
await test.roll();
if (test.failed)
{
this.actor.addCondition("prone");
}

View File

@@ -7,9 +7,9 @@ const test = await this.actor.setupSkill(game.i18n.localize("NAME.Résistance"),
}
});
await Test.roll();
await test.roll();
if (Test.Échoué) {
const SL = Number(Test.result.SL);
if (test.failed) {
const SL = Number(test.result.SL);
this.script.message(`Butcher perd ${SL} dents.`);
}

View File

@@ -1 +1 @@
,args.fields.slBonus++;,args.fields.slBonus++;,args.fields.slBonus++;
args.fields.slBonus++;

View File

@@ -7,8 +7,8 @@ let difficulty = ""
difficulty = "veasy"
let test = await this.actor.setupSkill(game.i18n.localize("NAME.Résistance"), {context : {failure : this.actor.name + " meurt de la Pourriture"}, fields: {difficulty}, appendTitle : " - Pourriture"})
await Test.roll();
if (Test.Échoué)
await test.roll();
if (test.failed)
{
this.actor.addCondition("dead");
}

View File

@@ -7,8 +7,8 @@ let difficulty = ""
difficulty = "veasy"
let test = await this.actor.setupSkill(game.i18n.localize("NAME.Résistance"), {context : {failure : this.actor.name + " meurt de la Pourriture"}, fields: {difficulty}, appendTitle : " - Pourriture"})
await Test.roll();
if (Test.Échoué)
await test.roll();
if (test.failed)
{
this.actor.addCondition("dead");
}

View File

@@ -1,7 +1,7 @@
let test = await this.actor.setupCharacteristic("i", {skipTargets: true, appendTitle : ` - ${this.effect.name}`, fields : {difficulty : "easy"}})
await Test.roll();
await test.roll();
if (!Test.succeeded)
if (!test.succeeded)
{
this.actor.addCondition("stunned");
}

View File

@@ -1,7 +1,7 @@
let test = await this.actor.setupCharacteristic("ag", {fields : {difficulty : "hard"}});
await Test.roll();
await test.roll();
if (Test.Échoué)
if (test.failed)
{
await this.actor.addCondition("bleeding")
await this.actor.addCondition("entangled")

View File

@@ -9,8 +9,8 @@ if (SL >= 3)
let test = await args.actor.setupCharacteristic("wp", {fields: {difficulty}, skipTargets: true, appendTitle : " - " + this.effect.name, context : {failure: "Reçoit un état Sonné"}})
await Test.roll();
if (Test.Échoué)
await test.roll();
if (test.failed)
{
args.actor.addCondition("stunned");
}

View File

@@ -12,7 +12,7 @@ const test = await this.actor.setupCharacteristic("t", {
}
});
await Test.roll();
if (Test.failure) {
await test.roll();
if (test.failure) {
await this.actor.addCondition("prone");
}

View File

@@ -1,6 +1,6 @@
let test = await this.actor.setupSkill("Résistance", {fields : {difficulty : "difficult", appendTitle : ` - ${this.effect.name}`}});
await Test.roll();
if (Test.Échoué)
await test.roll();
if (test.failed)
{
await this.actor.addCondition("blinded");
}

View File

@@ -1,8 +1,8 @@
let test = await this.actor.setupCharacteristic("wp", {skipTargets: true, appendTitle : ` - ${this.effect.name}`})
await Test.roll();
await test.roll();
let opposedResult = Test.opposedMessages[0]?.system.opposedHandler?.resultMessage?.system.opposedTest?.result
let opposedResult = test.opposedMessages[0]?.system.opposedHandler?.resultMessage?.system.opposedTest?.result
if (opposedResult?.winner == "attacker")
{

View File

@@ -1,7 +1,7 @@
let test = await this.actor.setupCharacteristic("t", { appendTitle: ` - ${this.effect.name}`, fields: { difficulty: "challenging" } })
await Test.roll();
await test.roll();
if (Test.Échoué)
if (test.failed)
{
let ageAdded = Math.ceil(CONFIG.Dice.randomUniform() * 10) + Math.ceil(CONFIG.Dice.randomUniform() * 10)
let ws = Math.ceil(CONFIG.Dice.randomUniform() * 10)

View File

@@ -1,5 +1,5 @@
if (args.opposedTest.result.differenceSL >= 0 && args.opposedTest.result.differenceSL <= 2 && args.opposedTest.result.winner == "attacker")
{
this.script.message(`Becomes lodged in the armour or flesh of the opponent. See @UUID[${this.item.uuid}]{${this.item.name}}.`, speaker : {alias : this.item.name}, {blind: true, whisper : ChatMessage.getWhisperRecipients("GM")})
this.script.message(`Becomes lodged in the armour or flesh of the opponent. See @UUID[${this.item.uuid}]{${this.item.name}}.`, {speaker : {alias : this.item.name}, blind: true, whisper : ChatMessage.getWhisperRecipients("GM")})
}

View File

@@ -1,7 +1,7 @@
let test = await this.actor.setupCharacteristic("wp", {skipTargets: true, appendTitle : ` - ${this.effect.name}`})
await Test.roll();
await test.roll();
// Kind of insane but whatever
let opposedResult = Test.opposedMessages[0]?.system.opposedHandler?.resultMessage?.system.opposedTest?.result
let opposedResult = test.opposedMessages[0]?.system.opposedHandler?.resultMessage?.system.opposedTest?.result
return opposedResult?.winner == "attacker";

View File

@@ -1,6 +1,6 @@
if (args.test.characteristicKey == "wp")
{
if (args.Test.Échoué)
if (args.test.failed)
{
let item = await fromUuid("Compendium.wfrp4e-core.items.AGcJl5rHjkyIQBPP")
let data = item.toObject();

View File

@@ -1,9 +1,9 @@
let location = this.item.system.location.key
let test = await this.actor.setupCharacteristic("dex", {context : {failure : `<strong>${this.effect.name}</strong>: Lâchez l'objet!`}, skipTargets: true, appendTitle : " - " + this.effect.name, fields : {difficulty : "average"}})
await Test.roll();
await test.roll();
if (location && Test.Échoué)
if (location && test.failed)
{
let dropped = this.item.system.weaponsAtLocation;

View File

@@ -1,6 +1,6 @@
if (args.test.characteristicKey == "wp")
{
if (args.Test.Échoué)
if (args.test.failed)
{
this.actor.createEmbeddedDocuments("ActiveEffect", [game.wfrp4e.config.symptomEffects["malaise"]])
this.script.message(`Test de FM échoué, <b>${this.actor.prototypeToken.name}</b> gains @Condition[Malaise] for [[1d10]] hours`, {whisper: ChatMessage.getWhisperRecipients("GM")})

View File

@@ -1,6 +1,6 @@
let test = await this.actor.setupSkill(game.i18n.localize("NAME.Cool"), {appendTitle : ` - ${this.effect.name}`, fields : {difficulty : "difficult", slBonus : -1 * this.effect.sourceTest.result.SL}})
await Test.roll();
if (Test.succeeded)
await test.roll();
if (test.succeeded)
{
this.script.notification(`Résistance à ${this.effect.name}`);
}

View File

@@ -1,8 +1,8 @@
if (args.totalWoundLoss > 0)
{
args.actor.setupCharacteristic("t", {skipTargets: true, appendTitle : ` - ${this.effect.name}`, fields: { difficulty: "difficult" } }).then(async Test => {
await Test.roll();
if (Test.Échoué)
await test.roll();
if (test.failed)
{
await args.actor.addCondition("poisoned")
this.script.message(await args.actor.applyBasicDamage(3, {suppressMsg : true, damageType: game.wfrp4e.config.DAMAGE_TYPE.IGNORE_ALL }))

View File

@@ -1,6 +1,6 @@
let test = await this.actor.setupCharacteristic("t", {skipTargets: true, appendTitle : ` - ${this.effect.name}`, fields : {difficulty : "hard"}})
await Test.roll();
if (Test.Échoué)
await test.roll();
if (test.failed)
{
let roll = await new Roll("1d10").roll({allowInteractive : false});
roll.toMessage(this.script.getChatData())

View File

@@ -1,2 +1,2 @@
args.totalWoundLoss = Math.max(0, args.totalWoundLoss - 1)
args.modifiers.other.push({label : this.effect.name, value : -1)
args.modifiers.other.push({label : this.effect.name, value : -1})

View File

@@ -1,8 +1,8 @@
let test = await this.actor.setupCharacteristic("t", {skipTargets: true, appendTitle : ` - ${this.effect.name}`, fields : {difficulty : "vhard"}});
await Test.roll();
await test.roll();
CorruptionMessageModel.createCorruptionMessage("minor", this.script.getChatData())
if (Test.Échoué)
if (test.failed)
{
this.actor.addCondition("unconscious");
}

View File

@@ -1,6 +1,6 @@
if (!this.item.name.includes("(") || this.item.system.tests.value.includes("(Sense)") || this.item.system.tests.value.toLowerCase().includes("(any)"))
{
let Tests = this.item.system.tests.value
let tests = this.item.system.tests.value
let name = this.item.name
// If name already specifies, make sure Tests value reflects that

2009
tools/check-tests-log.txt Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

111
tools/check-tests.js Normal file
View File

@@ -0,0 +1,111 @@
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const SCRIPTS_DIR = path.join(__dirname, '..', 'scripts');
const LOG_FILE = path.join(__dirname, 'check-tests-log.txt');
const log = [];
function writeLog(message) {
console.log(message);
log.push(message);
}
function getAllJsFiles(dir) {
const files = [];
function traverse(currentDir) {
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(currentDir, entry.name);
if (entry.isDirectory()) {
traverse(fullPath);
} else if (entry.isFile() && entry.name.endsWith('.js')) {
files.push(fullPath);
}
}
}
traverse(dir);
return files;
}
function checkForTests(filePath) {
const content = fs.readFileSync(filePath, 'utf-8');
return content.includes('let Tests');
}
// Programme principal
writeLog('='.repeat(60));
writeLog('VÉRIFICATION DE "let Tests" DANS LES SCRIPTS');
writeLog('='.repeat(60));
writeLog(`Date: ${new Date().toISOString()}`);
writeLog(`Répertoire: ${SCRIPTS_DIR}\n`);
const allFiles = getAllJsFiles(SCRIPTS_DIR);
writeLog(`Total de fichiers trouvés: ${allFiles.length}\n`);
const filesWithTests = [];
const filesWithoutTests = [];
allFiles.forEach(filePath => {
const relativePath = path.relative(path.join(__dirname, '..'), filePath);
if (checkForTests(filePath)) {
filesWithTests.push(relativePath);
} else {
filesWithoutTests.push(relativePath);
}
});
// Afficher les résultats
writeLog('=== FICHIERS CONTENANT "let Tests" ===\n');
if (filesWithTests.length > 0) {
filesWithTests.forEach(file => {
writeLog(`${file}`);
});
} else {
writeLog('Aucun fichier trouvé.');
}
writeLog(`\nTotal: ${filesWithTests.length} fichier(s)\n`);
writeLog('='.repeat(60));
writeLog('=== FICHIERS NE CONTENANT PAS "let Tests" ===\n');
if (filesWithoutTests.length > 0) {
filesWithoutTests.forEach(file => {
writeLog(`${file}`);
});
} else {
writeLog('Aucun fichier trouvé.');
}
writeLog(`\nTotal: ${filesWithoutTests.length} fichier(s)\n`);
writeLog('='.repeat(60));
writeLog('RÉSUMÉ');
writeLog('='.repeat(60));
writeLog(`Fichiers avec "let Tests": ${filesWithTests.length}`);
writeLog(`Fichiers sans "let Tests": ${filesWithoutTests.length}`);
writeLog(`Total de fichiers analysés: ${allFiles.length}`);
writeLog('='.repeat(60));
// Sauvegarder le log
fs.writeFileSync(LOG_FILE, log.join('\n'), 'utf-8');
writeLog(`\nLog sauvegardé dans: ${LOG_FILE}`);
// Exporter les résultats en JSON
const results = {
date: new Date().toISOString(),
totalFiles: allFiles.length,
filesWithTests: filesWithTests,
filesWithoutTests: filesWithoutTests
};
const resultsFile = path.join(__dirname, 'check-tests-results.json');
fs.writeFileSync(resultsFile, JSON.stringify(results, null, 2), 'utf-8');
writeLog(`Résultats sauvegardés dans: ${resultsFile}`);