Compare commits

...

9 Commits

Author SHA1 Message Date
df1e0b9952 Amélioration robustess et vérification sur import des modules
All checks were successful
Validation JSON / validate (push) Successful in 16s
Release Creation / build (release) Successful in 48s
2026-04-14 08:26:08 +02:00
b1e96af421 UPdsate pour support v14
All checks were successful
Validation JSON / validate (push) Successful in 15s
Release Creation / build (release) Successful in 49s
2026-04-11 20:23:24 +02:00
17d865b60b Fix sur maladies again
All checks were successful
Validation JSON / validate (push) Successful in 17s
Release Creation / build (release) Successful in 1m12s
2026-03-24 11:33:50 +01:00
5f4e0c7ce5 Nombreuses corrections sur les maladies et symptomes
All checks were successful
Validation JSON / validate (push) Successful in 24s
2026-03-22 20:41:58 +01:00
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
102 changed files with 12381 additions and 37726 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

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
.history/ .history/
.idea/ .idea/
.github/

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
{ {
"label": "Items (Lustria)", "label": "Items (Lustria)",
"folders": { "folders": {
"Careers": "Carrières", "Careers": "Carrières",
"Spells": "Sorts", "Spells": "Sorts",
"Trappings": "Possessions", "Trappings": "Possessions",
@@ -69,16 +69,10 @@
"converter": "generic_localization" "converter": "generic_localization"
}, },
"durationValue": "system.duration.value", "durationValue": "system.duration.value",
"durationUnit": { "durationUnit": "system.duration.unit",
"path": "system.duration.unit",
"converter": "disease_duration_unit"
},
"contraction": "system.contraction.value", "contraction": "system.contraction.value",
"incubationValue": "system.incubation.value", "incubationValue": "system.incubation.value",
"incubationUnit": { "incubationUnit": "system.incubation.unit",
"path": "system.incubation.unit",
"converter": "disease_duration_unit"
},
"symptoms": "system.symptoms.value", "symptoms": "system.symptoms.value",
"permanent": "system.permanent.value", "permanent": "system.permanent.value",
"special": "system.special.value", "special": "system.special.value",

View File

@@ -1,6 +1,6 @@
{ {
"label": "Items (Old World Bundle II)", "label": "Items (Old World Bundle II)",
"folders": { "folders": {
"Lore of the Beasts": "Domaine des Bêtes", "Lore of the Beasts": "Domaine des Bêtes",
"Lore of Death": "Domaine de la Mort", "Lore of Death": "Domaine de la Mort",
"Lore of Fire": "Domaine du Feu", "Lore of Fire": "Domaine du Feu",
@@ -78,16 +78,10 @@
"converter": "generic_localization" "converter": "generic_localization"
}, },
"durationValue": "system.duration.value", "durationValue": "system.duration.value",
"durationUnit": { "durationUnit": "system.duration.unit",
"path": "system.duration.unit",
"converter": "disease_duration_unit"
},
"contraction": "system.contraction.value", "contraction": "system.contraction.value",
"incubationValue": "system.incubation.value", "incubationValue": "system.incubation.value",
"incubationUnit": { "incubationUnit": "system.incubation.unit",
"path": "system.incubation.unit",
"converter": "disease_duration_unit"
},
"symptoms": "system.symptoms.value", "symptoms": "system.symptoms.value",
"permanent": "system.permanent.value", "permanent": "system.permanent.value",
"special": "system.special.value", "special": "system.special.value",

View File

@@ -1,6 +1,6 @@
{ {
"label": "Items (Imperial Zoo)", "label": "Items (Imperial Zoo)",
"folders": { "folders": {
"Ammunition": "Munitions", "Ammunition": "Munitions",
"Careers": "Carrières", "Careers": "Carrières",
"Prayers": "Prières", "Prayers": "Prières",
@@ -70,16 +70,10 @@
"converter": "generic_localization" "converter": "generic_localization"
}, },
"durationValue": "system.duration.value", "durationValue": "system.duration.value",
"durationUnit": { "durationUnit": "system.duration.unit",
"path": "system.duration.unit",
"converter": "disease_duration_unit"
},
"contraction": "system.contraction.value", "contraction": "system.contraction.value",
"incubationValue": "system.incubation.value", "incubationValue": "system.incubation.value",
"incubationUnit": { "incubationUnit": "system.incubation.unit",
"path": "system.incubation.unit",
"converter": "disease_duration_unit"
},
"symptoms": "system.symptoms.value", "symptoms": "system.symptoms.value",
"permanent": "system.permanent.value", "permanent": "system.permanent.value",
"special": "system.special.value", "special": "system.special.value",

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('');
});
}

4059
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", "url": "https://www.uberwald.me/gitea/public/foundryvtt-wh4-lang-fr-fr",
"version": "9.4.2", "version": "9.4.3",
"esmodules": [ "esmodules": [
"wh4_fr.js", "wh4_fr.js",
"modules/babele-register.js", "modules/babele-register.js",
@@ -119,12 +119,12 @@
"folders": [] "folders": []
} }
], ],
"manifest": "https://www.uberwald.me/gitea/public/foundryvtt-wh4-lang-fr-fr/raw/v10/module.json", "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/archive/foundryvtt-wh4-lang-fr-9-4-2.zip", "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", "id": "wh4-fr-translation",
"compatibility": { "compatibility": {
"minimum": "13", "minimum": "13",
"verified": "13" "verified": "14"
}, },
"relationships": { "relationships": {
"systems": [ "systems": [

View File

@@ -16,30 +16,27 @@ const _patch_eis = () => {
game.wfrp4e.config.symptomTreatment["swelling"] = "La plupart des traitements consistent à plonger la partie affectée, ou parfois tout le corps, dans un bain d'eau glacée pour réduire la chaleur qui accompagne les gonflements. Un <b> Test de Guérison Difficile (-20) étendu </b> nécessitant +3 DR réduit le renflement de <b> <a class ='chat-roll'> 2d10 </a> </b> heures. Chaque test dure une heure. Le patient se retrouve avec l'Etat Exténué +1 pour chaque test effectué au cours du processus. <br> <br> A la place, certains médecins saignent le patient avec une lame ou des sangsues. Un <b>Test de Guérison étendu </b> réussi nécessitant +4 SL et des Outils (médecin) réduit le renflement de (<a class ='chat-roll'> 1d10 </a> + Bonus d'Endurance du patient) heures. Chaque test a une difficulté de base <b> impossible (-50) </b> et dure une demi-heure."; game.wfrp4e.config.symptomTreatment["swelling"] = "La plupart des traitements consistent à plonger la partie affectée, ou parfois tout le corps, dans un bain d'eau glacée pour réduire la chaleur qui accompagne les gonflements. Un <b> Test de Guérison Difficile (-20) étendu </b> nécessitant +3 DR réduit le renflement de <b> <a class ='chat-roll'> 2d10 </a> </b> heures. Chaque test dure une heure. Le patient se retrouve avec l'Etat Exténué +1 pour chaque test effectué au cours du processus. <br> <br> A la place, certains médecins saignent le patient avec une lame ou des sangsues. Un <b>Test de Guérison étendu </b> réussi nécessitant +4 SL et des Outils (médecin) réduit le renflement de (<a class ='chat-roll'> 1d10 </a> + Bonus d'Endurance du patient) heures. Chaque test a une difficulté de base <b> impossible (-50) </b> et dure une demi-heure.";
game.wfrp4e.config.loreEffects["tzeentch"] = { game.wfrp4e.config.loreEffects["tzeentch"] = {
label: "Domaine de Tzeentch", name: "Domaine de Tzeentch",
icon: "modules/wfrp4e-core/icons/spells/tzeentch.png", img: "modules/wfrp4e-core/icons/spells/tzeentch.png",
transfer: true, system: {
flags: { transferData: {
wfrp4e: { type: "target"
"effectApplication": "apply", },
"effectTrigger": "oneTime", scriptData: [{
"lore": true, trigger: "immediate",
"script": ` label: "Test d'Endurance",
if (this.actor.isOwner) script: `
args.actor.setupSkill("Résistance", {context : {failure: "1 Point de Corruption reçu", success : "1 Point de Chance gagné"}}).then(setupData => { this.actor.setupSkill(game.i18n.localize("NAME.Endurance"), {appendTitle : " - " + this.effect.name, context : {failure: "1 Point de Corruption reçu", success : "1 Point de Chance gagné"}}).then(setupData => {
args.actor.basicTest(setupData).then(test => this.actor.basicTest(setupData).then(test => {
{ if (test.succeeded && this.actor.type == "character") {
if (test.result.result == "success" && args.actor.type == "character") this.actor.update({"system.status.fortune.value" : this.actor.system.status.fortune.value + 1})
{ } else if (test.failed && this.actor.type == "character") {
args.actor.update({"system.status.fortune.value" : args.actor.system.status.fortune.value + 1}) this.actor.update({"system.status.corruption.value" : this.actor.system.status.corruption.value + 1})
} }
else if (test.result.result == "failure" && args.actor.type == "character") })
{ })
args.actor.update({"system.status.corruption.value" : args.actor.system.status.corruption.value + 1}) return false;`
} }]
})
})`
}
} }
} }
} }
@@ -133,10 +130,10 @@ const __auto_patch_translation_journal_compendium = async (compmod) => {
if (game.user.isGM) { if (game.user.isGM) {
let compData = game.packs.get("WH4-fr-translation.tables-des-traductions"); let compData = game.packs.get("WH4-fr-translation.tables-des-traductions");
compData.locked = false; compData.locked = false;
let translEntries = await compData.getContent(); let translEntries = await compData.getDocuments();
for (let entryData of translEntries) { for (let entryData of translEntries) {
let mydata = foundry.utils.duplicate(entryData.data); let mydata = entryData.toObject();
mydata.content = mydata.content.replace(/wfrp4e-content/g, compmod); mydata.text.content = mydata.text.content.replace(/wfrp4e-content/g, compmod);
entryData.update(mydata); entryData.update(mydata);
} }
compData.locked = true; compData.locked = true;
@@ -175,9 +172,55 @@ const patch_core_tables = (tableList) => {
/************************************************************************************/ /************************************************************************************/
const patch_trade_gazeteer = () => { 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 => { 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;
}); });
} }
} }
@@ -358,6 +401,56 @@ Hooks.on('ready', () => {
// Patch function for effects // Patch function for effects
game.wfrp4e.utility.findKey = warhammer.utility.findKey game.wfrp4e.utility.findKey = warhammer.utility.findKey
// Patch SpellModel.computeSpellDamage to handle English characteristic bonus names.
// Babele instantiates actors TWICE: first with untranslated data (English formulas like
// "Willpower Bonus+4"), then with translated data. The first pass fails because
// characteristicsBonus values are already French ("Bonus de Force Mentale").
// This patch pre-replaces English bonus names with numeric values before the original
// formula evaluation runs, preventing SyntaxErrors and notification spam.
const __EN_BONUS_TO_CHAR = {
"weapon skill bonus": "ws", "ballistic skill bonus": "bs",
"strength bonus": "s", "toughness bonus": "t",
"initiative bonus": "i", "agility bonus": "ag",
"dexterity bonus": "dex", "intelligence bonus": "int",
"willpower bonus": "wp", "fellowship bonus": "fel"
};
const SpellModel = CONFIG.Item.dataModels?.["spell"];
if (SpellModel?.prototype?.computeSpellDamage) {
const _origComputeSpellDamage = SpellModel.prototype.computeSpellDamage;
SpellModel.prototype.computeSpellDamage = function(formula, options) {
if (typeof formula === "string") {
const actor = options?.actor || this.parent?.actor;
if (actor?.system?.characteristics) {
let f = formula.toLowerCase();
for (const [enName, ch] of Object.entries(__EN_BONUS_TO_CHAR)) {
if (f.includes(enName)) {
const bonus = actor.system.characteristics[ch]?.bonus ?? 0;
f = f.replace(enName, bonus);
}
}
formula = f;
}
}
return _origComputeSpellDamage.call(this, formula, options);
};
}
// Patch postSymptom to handle English symptom names in @Symptom[...] links.
// After i18nInit, config.symptoms values are French strings (e.g. "Fièvre"), so
// findKey("Fever", config.symptoms) fails. We normalize via game.i18n.localize first.
const _origPostSymptom = game.wfrp4e.utility.postSymptom.bind(game.wfrp4e.utility);
game.wfrp4e.utility.postSymptom = async function(symptom) {
const baseName = symptom.split("(")[0].trim();
const symkey = warhammer.utility.findKey(baseName, game.wfrp4e.config.symptoms);
if (!symkey) {
const localizedBase = game.i18n.localize(baseName);
if (localizedBase !== baseName) {
symptom = symptom.replace(baseName, localizedBase);
}
}
return _origPostSymptom(symptom);
};
/** New modifiers */ /** New modifiers */
game.wfrp4e.config.difficultyModifiers = { game.wfrp4e.config.difficultyModifiers = {
"veasy": 60, "veasy": 60,

View File

@@ -30,6 +30,20 @@ const __SELECT_BONUS_PREFIX_D = {
"agilité": 1 "agilité": 1
} }
// Map English characteristic names (as they appear in spell formulas) to WFRP4e abbreviations
const __CHAR_EN_TO_ABBR = {
"weapon skill": "ws",
"ballistic skill": "bs",
"strength": "s",
"toughness": "t",
"initiative": "i",
"agility": "ag",
"dexterity": "dex",
"intelligence": "int",
"willpower": "wp",
"fellowship": "fel"
}
/************************************************************************************/ /************************************************************************************/
export class WFRP4FrTranslation { export class WFRP4FrTranslation {
@@ -57,16 +71,23 @@ export class WFRP4FrTranslation {
if (value == "You") return "Vous"; // Hop ! if (value == "You") return "Vous"; // Hop !
if (value == "Instant") return "Instantané"; // Hop ! if (value == "Instant") return "Instantané"; // Hop !
let translw = value; let translw = value;
let re = /(.*)\s+[Bb]onus\s*(\w*)/i; let re = /(.*)\s+[Bb]onus\s*(.*)/i; // (.*) at end captures modifiers like "+4"
let res = re.exec(value); let res = re.exec(value);
let unit = ""; let unit = "";
if (res) { // Test "<charac> Bonus <unit>" pattern if (res) { // Test "<charac> Bonus <modifier>" pattern
if (res[1]) { // We have char name, then convert it if (res[1]) { // We have char name, then convert it
translw = game.i18n.localize(res[1].trim()); const charEN = res[1].trim().toLowerCase();
let bonusPrefix = (translw.toLowerCase() in __SELECT_BONUS_PREFIX_D) ? "Bonus d'" : "Bonus de "; const abbr = __CHAR_EN_TO_ABBR[charEN];
translw = bonusPrefix + translw if (abbr && game.wfrp4e?.config?.characteristicsBonus?.[abbr]) {
// Use the localized French bonus name from config (already resolved by localizeConfig at i18nInit)
translw = game.wfrp4e.config.characteristicsBonus[abbr];
} else {
translw = game.i18n.localize(res[1].trim());
let bonusPrefix = (translw.toLowerCase() in __SELECT_BONUS_PREFIX_D) ? "Bonus d'" : "Bonus de ";
translw = bonusPrefix + translw;
}
} }
unit = res[2]; unit = res[2]; // may be "+4", "-2", "2", "yards", etc.
} else { } else {
re = /(\d+) (\w+)/i; re = /(\d+) (\w+)/i;
res = re.exec(value); res = re.exec(value);
@@ -90,6 +111,8 @@ export class WFRP4FrTranslation {
if (unit == "Bonus") { // Another weird management if (unit == "Bonus") { // Another weird management
console.log("Translating bonus", unit); console.log("Translating bonus", unit);
translw = "Bonus de " + translw; translw = "Bonus de " + translw;
} else if (unit && /^[+\-*\/]/.test(unit)) {
translw += unit; // No space before operators like "+4"
} else { } else {
translw += " " + unit; translw += " " + unit;
} }
@@ -278,8 +301,25 @@ Hooks.once('init', () => {
"process_effects": (effectsData, translations, data, tc, tc_translations) => { "process_effects": (effectsData, translations, data, tc, tc_translations) => {
//console.log("Effects :", effectsData, translations, data, tc, tc_translations) //console.log("Effects :", effectsData, translations, data, tc, tc_translations)
for (let e of effectsData) { for (let e of effectsData) {
// Foundry v13 requires name; migrate legacy data where only label was stored
if (e.name == null) e.name = e.label || "";
let origName = e.name let origName = e.name
e.name = tc_translations.name || game.i18n.localize(e.name) // Symptom effects have their own name (Fever, Malaise, etc.) — don't overwrite with the parent item name
if (e.flags?.wfrp4e?.symptom) {
let symName = e.name;
let gravity = "";
if (symName.includes("(") && symName.includes(")")) {
let re = /(.*) +\((.*)\)/i;
let res = re.exec(symName);
if (res) {
symName = res[1].trim();
gravity = " (" + game.i18n.localize(res[2].trim()) + ")";
}
}
e.name = game.i18n.localize(symName) + gravity;
} else {
e.name = tc_translations.name || game.i18n.localize(e.name) || e.label || ""
}
if ( e.flags?.wfrp4e?.scriptData) { if ( e.flags?.wfrp4e?.scriptData) {
for (let script of e.flags.wfrp4e.scriptData) { for (let script of e.flags.wfrp4e.scriptData) {
if (script?.label) { if (script?.label) {
@@ -396,10 +436,18 @@ Hooks.once('init', () => {
return beast_traits return beast_traits
} }
//console.log("TRANS:", beast_traits) //console.log("TRANS:", beast_traits)
// Normalize: Foundry v13 requires ActiveEffect.name; migrate legacy v12 data
for (let trait_en of beast_traits) {
if (trait_en.effects) {
for (let eff of trait_en.effects) {
if (eff.name == null) eff.name = eff.label || "";
}
}
}
for (let trait_en of beast_traits) { for (let trait_en of beast_traits) {
let special = ""; let special = "";
let nbt = ""; let nbt = "";
let name_en = trait_en.name.trim(); // strip \r in some traits name let name_en = trait_en.name.replace(/\r/g, '').trim(); // strip \r (including internal) in some traits name
if (!trait_en.name || trait_en.name.length == 0) { if (!trait_en.name || trait_en.name.length == 0) {
console.log("Wrong item name found!!!!") console.log("Wrong item name found!!!!")
continue continue
@@ -415,8 +463,11 @@ Hooks.once('init', () => {
} else if (name_en.includes("(") && name_en.includes(")")) { // Then process specific traits name with (xxxx) inside } else if (name_en.includes("(") && name_en.includes(")")) { // Then process specific traits name with (xxxx) inside
let re = /(.*) \((.*)\)/i; let re = /(.*) \((.*)\)/i;
let res = re.exec(name_en); let res = re.exec(name_en);
name_en = res[1]; // Get the root traits name if (!res) { console.warn("WFRP4E-FR | bestiary_traits: regex failed for trait:", name_en); }
special = " (" + game.i18n.localize(res[2].trim()) + ")"; // And the special keyword else {
name_en = res[1]; // Get the root traits name
special = " (" + game.i18n.localize(res[2].trim()) + ")"; // And the special keyword
}
} }
let validCompendiums = game.wfrp4e.tags.getPacksWithTag("trait") let validCompendiums = game.wfrp4e.tags.getPacksWithTag("trait")
for (let compData of validCompendiums) { for (let compData of validCompendiums) {
@@ -438,8 +489,11 @@ Hooks.once('init', () => {
if (name_en.includes("(") && name_en.includes(")")) { // Then process specific skills name with (xxxx) inside if (name_en.includes("(") && name_en.includes(")")) { // Then process specific skills name with (xxxx) inside
let re = /(.*) +\((.*)\)/i; let re = /(.*) +\((.*)\)/i;
let res = re.exec(name_en); let res = re.exec(name_en);
name_en = res[1].trim(); // Get the root skill name if (!res) { console.warn("WFRP4E-FR | bestiary_traits: regex failed for skill:", name_en); }
special = " (" + game.i18n.localize(res[2].trim()) + ")"; // And the special keyword else {
name_en = res[1].trim(); // Get the root skill name
special = " (" + game.i18n.localize(res[2].trim()) + ")"; // And the special keyword
}
} }
let validCompendiums = game.wfrp4e.tags.getPacksWithTag("skill") let validCompendiums = game.wfrp4e.tags.getPacksWithTag("skill")
for (let compData of validCompendiums) { for (let compData of validCompendiums) {
@@ -484,8 +538,11 @@ Hooks.once('init', () => {
if (name_en.includes("(") && name_en.includes(")")) { // Then process specific skills name with (xxxx) inside if (name_en.includes("(") && name_en.includes(")")) { // Then process specific skills name with (xxxx) inside
let re = /(.*) +\((.*)\)/i; let re = /(.*) +\((.*)\)/i;
let res = re.exec(name_en); let res = re.exec(name_en);
name_en = res[1].trim(); // Get the root talent name, no parenthesis this time... if (!res) { console.warn("WFRP4E-FR | bestiary_traits: regex failed for talent:", name_en); }
special = " (" + game.i18n.localize(res[2].trim()) + ")"; // And the special keyword else {
name_en = res[1].trim(); // Get the root talent name, no parenthesis this time...
special = " (" + game.i18n.localize(res[2].trim()) + ")"; // And the special keyword
}
} }
let validCompendiums = game.wfrp4e.tags.getPacksWithTag("talent") let validCompendiums = game.wfrp4e.tags.getPacksWithTag("talent")
for (let compData of validCompendiums) { for (let compData of validCompendiums) {
@@ -650,15 +707,15 @@ Hooks.once('init', () => {
if (!effects) return; if (!effects) return;
for (const element of effects) { for (const element of effects) {
let effect = element; let effect = element;
let label = effect.label; let name = effect.name || effect.label;
let gravity = ""; let gravity = "";
if (label.includes("(") && label.includes(")")) { // Then process specific skills name with (xxxx) inside if (name.includes("(") && name.includes(")")) {
let re = /(.*) +\((.*)\)/i; let re = /(.*) +\((.*)\)/i;
let res = re.exec(label); let res = re.exec(name);
label = res[1].trim(); // Get the gravity name = res[1].trim();
gravity = " (" + game.i18n.localize(res[2].trim()) + ")"; // And the special keyword gravity = " (" + game.i18n.localize(res[2].trim()) + ")";
} }
effect.label = game.i18n.localize(label) + gravity; effect.name = game.i18n.localize(name) + gravity;
} }
}, },
// Auto-translate duration // Auto-translate duration

View File

@@ -145,6 +145,39 @@ export class WH4FRPatchConfig {
} }
} }
/************************************************************************************/
static patch_symptom_severity() {
// The core module's symptomEffects scripts check for English severity terms
// ("Moderate", "Severe") in this.effect.name. French disease compendiums use
// translated severity ("Modéré(e)", "Grave"), so the checks would fail.
// We patch the relevant scriptData to also check for French severity terms.
const effects = game.wfrp4e.config.symptomEffects;
if (!effects) return;
// Patch blight: checks Moderate → easy, Severe → average, else → veasy
for (const key of ["blight", "gangrene"]) {
const effect = effects[key];
if (!effect?.system?.scriptData) continue;
for (const sd of effect.system.scriptData) {
if (sd.script && sd.script.includes('.includes("Moderate")')) {
sd.script = sd.script
.replace('includes("Moderate")', 'includes("Moderate") || this.effect.name.includes("Modéré")')
.replace('includes("Severe")', 'includes("Severe") || this.effect.name.includes("Grave")');
}
}
}
// Patch convulsions: checks Moderate → -20, else → -10
if (effects.convulsions?.system?.scriptData) {
for (const sd of effects.convulsions.system.scriptData) {
if (sd.script && sd.script.includes('.includes("Moderate")')) {
sd.script = sd.script
.replace('includes("Moderate")', 'includes("Moderate") || this.effect.name.includes("Modéré")');
}
}
}
}
/************************************************************************************/ /************************************************************************************/
static fixSpeciesTable() { static fixSpeciesTable() {
@@ -192,16 +225,15 @@ export class WH4FRPatchConfig {
} }
if (game.wfrp4e.config.loreEffects) { if (game.wfrp4e.config.loreEffects) {
game.wfrp4e.config.loreEffects["beasts"].label = "Domaine des Bêtes" game.wfrp4e.config.loreEffects["beasts"].name = "Domaine des Bêtes"
game.wfrp4e.config.loreEffects["death"].label = "Domaine de la Mort" game.wfrp4e.config.loreEffects["death"].name = "Domaine de la Mort"
game.wfrp4e.config.loreEffects["fire"].label = "Domaine du Feu" game.wfrp4e.config.loreEffects["fire"].name = "Domaine du Feu"
game.wfrp4e.config.loreEffects["metal"].label = "Domaine du Métal" game.wfrp4e.config.loreEffects["metal"].name = "Domaine du Métal"
game.wfrp4e.config.loreEffects["heavens"].label = "Domaine des Cieux" game.wfrp4e.config.loreEffects["heavens"].name = "Domaine des Cieux"
game.wfrp4e.config.loreEffects["life"].label = "Domaine de la Vie" game.wfrp4e.config.loreEffects["life"].name = "Domaine de la Vie"
game.wfrp4e.config.loreEffects["light"].label = "Domaine de la Lumière" game.wfrp4e.config.loreEffects["light"].name = "Domaine de la Lumière"
game.wfrp4e.config.loreEffects["shadow"].label = "Domaine des Ombres" game.wfrp4e.config.loreEffects["shadow"].name = "Domaine des Ombres"
game.wfrp4e.config.loreEffects["hedgecraft"].label = "Domaine de la Magie de Village" game.wfrp4e.config.loreEffects["hedgecraft"].name = "Domaine de la Sorcellerie"
game.wfrp4e.config.loreEffects["hedgecraft"].label = "Domaine de la Sorcellerie"
} }
if (game.wfrp4e.config.species) { if (game.wfrp4e.config.species) {
@@ -240,276 +272,10 @@ export class WH4FRPatchConfig {
this.patch_career(); this.patch_career();
game.wfrp4e.config.symptomEffects = { // Patch symptom severity scripts to support French severity terms
"blight": { // The core module scripts check for "Moderate"/"Severe" in effect.name,
label: "Toxine", // but French disease compendiums use "Modéré(e)"/"Grave" instead.
icon: "modules/wfrp4e-core/icons/diseases/disease.png", this.patch_symptom_severity();
transfer: true,
flags: {
wfrp4e: {
"effectApplication": "actor",
"effectTrigger": "invoke",
"symptom": true,
"script": `
let difficulty = ""
if (this.effect.label.includes("Modéré"))
difficulty = "easy"
else if (this.effect.label.includes("Sévère"))
difficulty = "average"
else
difficulty = "veasy"
if (args.actor.isOwner)
{
args.actor.setupSkill("Résistance", {absolute: {difficulty}}).then(setupData => {
args.actor.basicTest(setupData).then(test =>
{
if (test.result.outcome == "failure")
args.actor.addCondition("dead")
})
})
}`
}
}
},
"buboes": {
label: "Bubons",
icon: "modules/wfrp4e-core/icons/diseases/disease.png",
transfer: true,
flags: {
wfrp4e: {
"effectApplication": "actor",
"effectTrigger": "prefillDialog",
"symptom": true,
"script": `
let applicableCharacteristics = ["ws", "bs", "s", "fel", "ag", "t", "dex"]
if (args.type == "weapon")
args.prefillModifiers.modifier -= 10
else if (args.type == "characteristic")
{
if (applicableCharacteristics.includes(args.item))
args.prefillModifiers.modifier -= 10
}
else if (args.type == "skill")
{
if (applicableCharacteristics.includes(args.item.characteristic.value))
args.prefillModifiers.modifier -= 10
}
`}
}
},
"convulsions": {
label: "Convulsions",
icon: "modules/wfrp4e-core/icons/diseases/disease.png",
transfer: true,
flags: {
wfrp4e: {
"effectApplication": "actor",
"effectTrigger": "prefillDialog",
"symptom": true,
"script": `
let modifier = 0
if (this.effect.label.includes("Modéré"))
modifier = -20
else
modifier = -10
let applicableCharacteristics = ["ws", "bs", "s", "ag", "t", "dex"]
if (args.type == "weapon")
args.prefillModifiers.modifier += modifier
else if (args.type == "characteristic")
{
if (applicableCharacteristics.includes(args.item))
args.prefillModifiers.modifier += modifier
}
else if (args.type == "skill")
{
if (applicableCharacteristics.includes(args.item.characteristic.value))
args.prefillModifiers.modifier += modifier
}
}`
}
}
},
"fever": {
label: "Fièvre",
icon: "modules/wfrp4e-core/icons/diseases/disease.png",
transfer: true,
flags: {
wfrp4e: {
"effectApplication": "actor",
"effectTrigger": "prefillDialog",
"symptom": true,
"script": `
let applicableCharacteristics = ["ws", "bs", "s", "fel", "ag", "t", "dex"]
if (args.type == "weapon")
args.prefillModifiers.modifier -= 10
else if (args.type == "characteristic")
{
if (applicableCharacteristics.includes(args.item))
args.prefillModifiers.modifier -= 10
}
else if (args.type == "skill")
{
if (applicableCharacteristics.includes(args.item.characteristic.value))
args.prefillModifiers.modifier -= 10
}`,
"otherEffects": ["blight", "wounded"]
}
}
},
"flux": {
label: "Intoxication Alimentaire",
icon: "modules/wfrp4e-core/icons/diseases/disease.png",
transfer: true,
flags: {
wfrp4e: {
"symptom": true
}
}
},
"lingering": {
label: "Persistant",
icon: "modules/wfrp4e-core/icons/diseases/disease.png",
transfer: true,
flags: {
wfrp4e: {
"symptom": true
}
}
},
"coughsAndSneezes": {
label: "Toux et éternuements",
icon: "modules/wfrp4e-core/icons/diseases/disease.png",
transfer: true,
flags: {
wfrp4e: {
"symptom": true
}
}
},
"gangrene": {
label: "Gangrène",
icon: "modules/wfrp4e-core/icons/diseases/disease.png",
transfer: true,
flags: {
wfrp4e: {
"effectApplication": "actor",
"effectTrigger": "prefillDialog",
"symptom": true,
"script": `
if (args.type == "characteristic" && args.item == "fel")
{
if (args.item == "fel")
args.prefillModifiers.modifier -= 10
}
else if (args.type == "skill")
{
if (args.item.characteristic.value == "fel")
args.prefillModifiers.modifier -= 10
}
}`
}
}
},
"malaise": {
label: "Malaise",
icon: "modules/wfrp4e-core/icons/diseases/disease.png",
transfer: true,
flags: {
wfrp4e: {
"effectApplication": "actor",
"effectTrigger": "prepareData",
"symptom": true,
"script": `
if (game.user.isUniqueGM)
{
let fatigued = args.actor.hasCondition("fatigued")
if (!fatigued)
{
args.actor.addCondition("fatigued")
ui.notifications.notify("Etat Extenué ajouté à " + args.actor.name + ", qui ne peut pas être enlevé tant que le symptôme Malaise est présent.")
}
}
`
}
}
},
"nausea": {
label: "Nausée",
icon: "modules/wfrp4e-core/icons/diseases/disease.png",
transfer: true,
flags: {
wfrp4e: {
"effectApplication": "actor",
"effectTrigger": "rollTest",
"symptom": true,
"script": `
if (this.actor.isOwner && args.test.result.outcome == "failure")
{
let applicableCharacteristics = ["ws", "bs", "s", "fel", "ag", "t", "dex"]
if (applicableCharacteristics.includes(args.test.result.characteristic))
this.actor.addCondition("stunned")
else if (args.test.result.skill && applicableCharacteristics.includes(args.test.result.skill.system.characteristic.value))
this.actor.addCondition("stunned")
else if (args.test.result.weapon)
this.actor.addCondition("stunned")
}
`
}
}
},
"pox": {
label: "Démangeaisons",
icon: "modules/wfrp4e-core/icons/diseases/disease.png",
transfer: true,
flags: {
wfrp4e: {
"effectApplication": "actor",
"effectTrigger": "prefillDialog",
"symptom": true,
"script": `
if (args.type == "characteristic" && args.item == "fel")
args.prefillModifiers.modifier -= 10
else if (args.type == "skill")
{
if (args.item.characteristic.value == "fel")
args.prefillModifiers.modifier -= 10
}
}`
}
}
},
"wounded": {
label: "Blessé",
icon: "modules/wfrp4e-core/icons/diseases/disease.png",
transfer: true,
flags: {
wfrp4e: {
"effectApplication": "actor",
"effectTrigger": "invoke",
"symptom": true,
"script": `
if (args.actor.isOwner)
{
args.actor.setupSkill("Résistance", {absolute: {difficulty : "average"}}).then(setupData => {
args.actor.basicTest(setupData).then(test =>
{
if (test.result.outcome == "failure")
fromUuid("Compendium.wfrp4e-core.diseases.kKccDTGzWzSXCBOb").then(disease => {
args.actor.createEmbeddedDocuments("Item", [disease.toObject()])
})
})
})
}`
}
}
}
}
game.wfrp4e.config.effectApplication = { game.wfrp4e.config.effectApplication = {
"actor": "Acteur", "actor": "Acteur",

View File

@@ -155,7 +155,7 @@ export default class InnRoller {
} }
// Extraire les informations du résultat // Extraire les informations du résultat
const resultText = rollResult.results[0]?.text || "Résultat inconnu"; const resultText = rollResult.results[0]?.name || rollResult.results[0]?.description || "Résultat inconnu";
const rollFormula = rollResult.roll?.formula || "1d100"; const rollFormula = rollResult.roll?.formula || "1d100";
const rollTotal = rollResult.roll?.total || 0; const rollTotal = rollResult.roll?.total || 0;
@@ -349,7 +349,7 @@ export default class InnRoller {
if (rollTable) { if (rollTable) {
try { try {
const roll = await rollTable.draw({ displayChat: false }); const roll = await rollTable.draw({ displayChat: false });
const resultText = roll.results[0]?.text || "Résultat inconnu"; const resultText = roll.results[0]?.name || roll.results[0]?.description || "Résultat inconnu";
results.push({ results.push({
category: this.getCategoryName(tableName), category: this.getCategoryName(tableName),
name: resultText, name: resultText,

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
MANIFEST-001299 MANIFEST-001339

View File

@@ -1,7 +1,7 @@
2026/03/04-00:01:24.197108 7f56f9bff6c0 Recovering log #1297 2026/04/13-23:10:07.603169 7fddd97be6c0 Recovering log #1337
2026/03/04-00:01:24.207650 7f56f9bff6c0 Delete type=3 #1295 2026/04/13-23:10:07.613544 7fddd97be6c0 Delete type=3 #1335
2026/03/04-00:01:24.207718 7f56f9bff6c0 Delete type=0 #1297 2026/04/13-23:10:07.613619 7fddd97be6c0 Delete type=0 #1337
2026/03/04-00:08:22.861497 7f54e37ef6c0 Level-0 table #1302: started 2026/04/13-23:14:52.439353 7fddca1c26c0 Level-0 table #1342: started
2026/03/04-00:08:22.861539 7f54e37ef6c0 Level-0 table #1302: 0 bytes OK 2026/04/13-23:14:52.439375 7fddca1c26c0 Level-0 table #1342: 0 bytes OK
2026/03/04-00:08:22.902864 7f54e37ef6c0 Delete type=0 #1300 2026/04/13-23:14:52.447401 7fddca1c26c0 Delete type=0 #1340
2026/03/04-00:08:22.939799 7f54e37ef6c0 Manual compaction at level-0 from '!journal!3IgmiprzLB6Lwenc' @ 72057594037927935 : 1 .. '!journal.pages!suuYN87Al1ZZWtQQ.jhgNnhWhrkOpKs1B' @ 0 : 0; will stop at (end) 2026/04/13-23:14:52.447538 7fddca1c26c0 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:04:24.137615 7f63f7fff6c0 Recovering log #1293 2026/04/13-23:01:32.388566 7fddd97be6c0 Recovering log #1333
2026/02/26-22:04:24.149067 7f63f7fff6c0 Delete type=3 #1291 2026/04/13-23:01:32.399282 7fddd97be6c0 Delete type=3 #1331
2026/02/26-22:04:24.149129 7f63f7fff6c0 Delete type=0 #1293 2026/04/13-23:01:32.399346 7fddd97be6c0 Delete type=0 #1333
2026/02/26-22:04:46.481770 7f61f6fff6c0 Level-0 table #1298: started 2026/04/13-23:07:12.207745 7fddca1c26c0 Level-0 table #1338: started
2026/02/26-22:04:46.481795 7f61f6fff6c0 Level-0 table #1298: 0 bytes OK 2026/04/13-23:07:12.207766 7fddca1c26c0 Level-0 table #1338: 0 bytes OK
2026/02/26-22:04:46.488240 7f61f6fff6c0 Delete type=0 #1296 2026/04/13-23:07:12.214487 7fddca1c26c0 Delete type=0 #1336
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/04/13-23:07:12.214671 7fddca1c26c0 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-001301 MANIFEST-001341

View File

@@ -1,7 +1,7 @@
2026/03/04-00:01:24.215723 7f56f93fe6c0 Recovering log #1299 2026/04/13-23:10:07.616013 7fddcbfff6c0 Recovering log #1339
2026/03/04-00:01:24.225890 7f56f93fe6c0 Delete type=3 #1297 2026/04/13-23:10:07.625710 7fddcbfff6c0 Delete type=3 #1337
2026/03/04-00:01:24.225964 7f56f93fe6c0 Delete type=0 #1299 2026/04/13-23:10:07.625777 7fddcbfff6c0 Delete type=0 #1339
2026/03/04-00:08:22.071002 7f54e37ef6c0 Level-0 table #1304: started 2026/04/13-23:14:52.426320 7fddca1c26c0 Level-0 table #1344: started
2026/03/04-00:08:22.071038 7f54e37ef6c0 Level-0 table #1304: 0 bytes OK 2026/04/13-23:14:52.426354 7fddca1c26c0 Level-0 table #1344: 0 bytes OK
2026/03/04-00:08:22.104811 7f54e37ef6c0 Delete type=0 #1302 2026/04/13-23:14:52.432796 7fddca1c26c0 Delete type=0 #1342
2026/03/04-00:08:22.138957 7f54e37ef6c0 Manual compaction at level-0 from '!folders!3uquYH73ttCdoH0I' @ 72057594037927935 : 1 .. '!items!ylFhk7mGZOnAJTUT' @ 0 : 0; will stop at (end) 2026/04/13-23:14:52.447521 7fddca1c26c0 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:04:24.151462 7f640d3fe6c0 Recovering log #1295 2026/04/13-23:01:32.401911 7fddd8fbd6c0 Recovering log #1335
2026/02/26-22:04:24.164087 7f640d3fe6c0 Delete type=3 #1293 2026/04/13-23:01:32.411157 7fddd8fbd6c0 Delete type=3 #1333
2026/02/26-22:04:24.164148 7f640d3fe6c0 Delete type=0 #1295 2026/04/13-23:01:32.411219 7fddd8fbd6c0 Delete type=0 #1335
2026/02/26-22:04:46.511516 7f61f6fff6c0 Level-0 table #1300: started 2026/04/13-23:07:12.194188 7fddca1c26c0 Level-0 table #1340: started
2026/02/26-22:04:46.511542 7f61f6fff6c0 Level-0 table #1300: 0 bytes OK 2026/04/13-23:07:12.194235 7fddca1c26c0 Level-0 table #1340: 0 bytes OK
2026/02/26-22:04:46.518083 7f61f6fff6c0 Delete type=0 #1298 2026/04/13-23:07:12.201298 7fddca1c26c0 Delete type=0 #1338
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/04/13-23:07:12.214646 7fddca1c26c0 Manual compaction at level-0 from '!folders!3uquYH73ttCdoH0I' @ 72057594037927935 : 1 .. '!items!ylFhk7mGZOnAJTUT' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-001299 MANIFEST-001339

View File

@@ -1,7 +1,7 @@
2026/03/04-00:01:24.249439 7f56e3fff6c0 Recovering log #1297 2026/04/13-23:10:07.641322 7fddd9fbf6c0 Recovering log #1337
2026/03/04-00:01:24.259919 7f56e3fff6c0 Delete type=3 #1295 2026/04/13-23:10:07.651537 7fddd9fbf6c0 Delete type=3 #1335
2026/03/04-00:01:24.259974 7f56e3fff6c0 Delete type=0 #1297 2026/04/13-23:10:07.651623 7fddd9fbf6c0 Delete type=0 #1337
2026/03/04-00:08:22.139094 7f54e37ef6c0 Level-0 table #1302: started 2026/04/13-23:14:52.478583 7fddca1c26c0 Level-0 table #1342: started
2026/03/04-00:08:22.139129 7f54e37ef6c0 Level-0 table #1302: 0 bytes OK 2026/04/13-23:14:52.478613 7fddca1c26c0 Level-0 table #1342: 0 bytes OK
2026/03/04-00:08:22.192132 7f54e37ef6c0 Delete type=0 #1300 2026/04/13-23:14:52.484781 7fddca1c26c0 Delete type=0 #1340
2026/03/04-00:08:22.365177 7f54e37ef6c0 Manual compaction at level-0 from '!journal!cZtNgayIw2QFhC9u' @ 72057594037927935 : 1 .. '!journal.pages!cZtNgayIw2QFhC9u.ts265H1XkisLgdow' @ 0 : 0; will stop at (end) 2026/04/13-23:14:52.484989 7fddca1c26c0 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:04:24.183291 7f640dbff6c0 Recovering log #1293 2026/04/13-23:01:32.426243 7fddcbfff6c0 Recovering log #1333
2026/02/26-22:04:24.198373 7f640dbff6c0 Delete type=3 #1291 2026/04/13-23:01:32.436951 7fddcbfff6c0 Delete type=3 #1331
2026/02/26-22:04:24.198448 7f640dbff6c0 Delete type=0 #1293 2026/04/13-23:01:32.437016 7fddcbfff6c0 Delete type=0 #1333
2026/02/26-22:04:46.518228 7f61f6fff6c0 Level-0 table #1298: started 2026/04/13-23:07:12.201427 7fddca1c26c0 Level-0 table #1338: started
2026/02/26-22:04:46.518251 7f61f6fff6c0 Level-0 table #1298: 0 bytes OK 2026/04/13-23:07:12.201453 7fddca1c26c0 Level-0 table #1338: 0 bytes OK
2026/02/26-22:04:46.524767 7f61f6fff6c0 Delete type=0 #1296 2026/04/13-23:07:12.207634 7fddca1c26c0 Delete type=0 #1336
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/04/13-23:07:12.214659 7fddca1c26c0 Manual compaction at level-0 from '!journal!cZtNgayIw2QFhC9u' @ 72057594037927935 : 1 .. '!journal.pages!cZtNgayIw2QFhC9u.ts265H1XkisLgdow' @ 0 : 0; will stop at (end)

View File

View File

View File

@@ -1 +1 @@
MANIFEST-001299 MANIFEST-001339

View File

@@ -1,7 +1,7 @@
2026/03/04-00:01:24.180286 7f56e3fff6c0 Recovering log #1297 2026/04/13-23:10:07.590923 7fddd8fbd6c0 Recovering log #1337
2026/03/04-00:01:24.190010 7f56e3fff6c0 Delete type=3 #1295 2026/04/13-23:10:07.600770 7fddd8fbd6c0 Delete type=3 #1335
2026/03/04-00:01:24.190063 7f56e3fff6c0 Delete type=0 #1297 2026/04/13-23:10:07.600832 7fddd8fbd6c0 Delete type=0 #1337
2026/03/04-00:08:22.033573 7f54e37ef6c0 Level-0 table #1302: started 2026/04/13-23:14:52.419409 7fddca1c26c0 Level-0 table #1342: started
2026/03/04-00:08:22.033610 7f54e37ef6c0 Level-0 table #1302: 0 bytes OK 2026/04/13-23:14:52.419440 7fddca1c26c0 Level-0 table #1342: 0 bytes OK
2026/03/04-00:08:22.070732 7f54e37ef6c0 Delete type=0 #1300 2026/04/13-23:14:52.426167 7fddca1c26c0 Delete type=0 #1340
2026/03/04-00:08:22.138944 7f54e37ef6c0 Manual compaction at level-0 from '!journal!50u8VAjdmovyr0hx' @ 72057594037927935 : 1 .. '!journal.pages!yzw9I0r3hCK7PJnz.sPNCYj2nR3Cp3jHd' @ 0 : 0; will stop at (end) 2026/04/13-23:14:52.447511 7fddca1c26c0 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:04:24.123515 7f640d3fe6c0 Recovering log #1293 2026/04/13-23:01:32.376215 7fddcbfff6c0 Recovering log #1333
2026/02/26-22:04:24.135202 7f640d3fe6c0 Delete type=3 #1291 2026/04/13-23:01:32.386265 7fddcbfff6c0 Delete type=3 #1331
2026/02/26-22:04:24.135283 7f640d3fe6c0 Delete type=0 #1293 2026/04/13-23:01:32.386335 7fddcbfff6c0 Delete type=0 #1333
2026/02/26-22:04:46.488408 7f61f6fff6c0 Level-0 table #1298: started 2026/04/13-23:07:12.172988 7fddca1c26c0 Level-0 table #1338: started
2026/02/26-22:04:46.488442 7f61f6fff6c0 Level-0 table #1298: 0 bytes OK 2026/04/13-23:07:12.173015 7fddca1c26c0 Level-0 table #1338: 0 bytes OK
2026/02/26-22:04:46.495308 7f61f6fff6c0 Delete type=0 #1296 2026/04/13-23:07:12.180381 7fddca1c26c0 Delete type=0 #1336
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/04/13-23:07:12.187032 7fddca1c26c0 Manual compaction at level-0 from '!journal!50u8VAjdmovyr0hx' @ 72057594037927935 : 1 .. '!journal.pages!yzw9I0r3hCK7PJnz.sPNCYj2nR3Cp3jHd' @ 0 : 0; will stop at (end)

View File

View File

View File

@@ -1 +1 @@
MANIFEST-001299 MANIFEST-001339

View File

@@ -1,7 +1,7 @@
2026/03/04-00:01:24.164425 7f56f93fe6c0 Recovering log #1297 2026/04/13-23:10:07.578503 7fddd9fbf6c0 Recovering log #1337
2026/03/04-00:01:24.174481 7f56f93fe6c0 Delete type=3 #1295 2026/04/13-23:10:07.588788 7fddd9fbf6c0 Delete type=3 #1335
2026/03/04-00:01:24.174536 7f56f93fe6c0 Delete type=0 #1297 2026/04/13-23:10:07.588855 7fddd9fbf6c0 Delete type=0 #1337
2026/03/04-00:08:21.946425 7f54e37ef6c0 Level-0 table #1302: started 2026/04/13-23:14:52.432890 7fddca1c26c0 Level-0 table #1342: started
2026/03/04-00:08:21.946466 7f54e37ef6c0 Level-0 table #1302: 0 bytes OK 2026/04/13-23:14:52.432912 7fddca1c26c0 Level-0 table #1342: 0 bytes OK
2026/03/04-00:08:21.989164 7f54e37ef6c0 Delete type=0 #1300 2026/04/13-23:14:52.439225 7fddca1c26c0 Delete type=0 #1340
2026/03/04-00:08:21.989360 7f54e37ef6c0 Manual compaction at level-0 from '!tables!4l60Lxv8cpsyy2Cg' @ 72057594037927935 : 1 .. '!tables.results!tfaYKDZqu7kgZvRG.yvbwKursaixh2dby' @ 0 : 0; will stop at (end) 2026/04/13-23:14:52.447529 7fddca1c26c0 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:04:24.106231 7f640dbff6c0 Recovering log #1293 2026/04/13-23:01:32.363321 7fddd9fbf6c0 Recovering log #1333
2026/02/26-22:04:24.120853 7f640dbff6c0 Delete type=3 #1291 2026/04/13-23:01:32.373224 7fddd9fbf6c0 Delete type=3 #1331
2026/02/26-22:04:24.120905 7f640dbff6c0 Delete type=0 #1293 2026/04/13-23:01:32.373285 7fddd9fbf6c0 Delete type=0 #1333
2026/02/26-22:04:46.475371 7f61f6fff6c0 Level-0 table #1298: started 2026/04/13-23:07:12.180494 7fddca1c26c0 Level-0 table #1338: started
2026/02/26-22:04:46.475399 7f61f6fff6c0 Level-0 table #1298: 0 bytes OK 2026/04/13-23:07:12.180514 7fddca1c26c0 Level-0 table #1338: 0 bytes OK
2026/02/26-22:04:46.481643 7f61f6fff6c0 Delete type=0 #1296 2026/04/13-23:07:12.186759 7fddca1c26c0 Delete type=0 #1336
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/04/13-23:07:12.187045 7fddca1c26c0 Manual compaction at level-0 from '!tables!4l60Lxv8cpsyy2Cg' @ 72057594037927935 : 1 .. '!tables.results!tfaYKDZqu7kgZvRG.yvbwKursaixh2dby' @ 0 : 0; will stop at (end)

View File

View File

View File

@@ -1 +1 @@
MANIFEST-000942 MANIFEST-000982

View File

@@ -1,7 +1,7 @@
2026/03/04-00:01:24.231380 7f56f9bff6c0 Recovering log #940 2026/04/13-23:10:07.628261 7fddd97be6c0 Recovering log #980
2026/03/04-00:01:24.242231 7f56f9bff6c0 Delete type=3 #938 2026/04/13-23:10:07.638743 7fddd97be6c0 Delete type=3 #978
2026/03/04-00:01:24.242297 7f56f9bff6c0 Delete type=0 #940 2026/04/13-23:10:07.638813 7fddd97be6c0 Delete type=0 #980
2026/03/04-00:08:22.105094 7f54e37ef6c0 Level-0 table #945: started 2026/04/13-23:14:52.447639 7fddca1c26c0 Level-0 table #985: started
2026/03/04-00:08:22.105137 7f54e37ef6c0 Level-0 table #945: 0 bytes OK 2026/04/13-23:14:52.447658 7fddca1c26c0 Level-0 table #985: 0 bytes OK
2026/03/04-00:08:22.138651 7f54e37ef6c0 Delete type=0 #943 2026/04/13-23:14:52.454058 7fddca1c26c0 Delete type=0 #983
2026/03/04-00:08:22.138969 7f54e37ef6c0 Manual compaction at level-0 from '!journal!056ILNNrLiPq3Gi3' @ 72057594037927935 : 1 .. '!journal.pages!yfZxl4I7XAuUF6r3.apXmOlZRmGT4GreB' @ 0 : 0; will stop at (end) 2026/04/13-23:14:52.484949 7fddca1c26c0 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:04:24.166725 7f63f7fff6c0 Recovering log #936 2026/04/13-23:01:32.413810 7fddd97be6c0 Recovering log #976
2026/02/26-22:04:24.181007 7f63f7fff6c0 Delete type=3 #934 2026/04/13-23:01:32.423395 7fddd97be6c0 Delete type=3 #974
2026/02/26-22:04:24.181079 7f63f7fff6c0 Delete type=0 #936 2026/04/13-23:01:32.423455 7fddd97be6c0 Delete type=0 #976
2026/02/26-22:04:46.525121 7f61f6fff6c0 Level-0 table #941: started 2026/04/13-23:07:12.187249 7fddca1c26c0 Level-0 table #981: started
2026/02/26-22:04:46.525166 7f61f6fff6c0 Level-0 table #941: 0 bytes OK 2026/04/13-23:07:12.187284 7fddca1c26c0 Level-0 table #981: 0 bytes OK
2026/02/26-22:04:46.532271 7f61f6fff6c0 Delete type=0 #939 2026/04/13-23:07:12.194022 7fddca1c26c0 Delete type=0 #979
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/04/13-23:07:12.214628 7fddca1c26c0 Manual compaction at level-0 from '!journal!056ILNNrLiPq3Gi3' @ 72057594037927935 : 1 .. '!journal.pages!yfZxl4I7XAuUF6r3.apXmOlZRmGT4GreB' @ 0 : 0; will stop at (end)

View File

@@ -14,7 +14,7 @@
let updateObj = this.actor.toObject(); 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) 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é"}}) let test = await args.actor.setupCharacteristic("wp", {skipTargets: true, appendTitle : " - " + this.effect.name, context : {failure: "Gain de 1 état Sonné"}})
await Test.roll(); await test.roll();
if (Test.Échoué) if (test.failed)
{ {
args.actor.addCondition("stunned") args.actor.addCondition("stunned")
} }

View File

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

View File

@@ -10,17 +10,17 @@ scriptData[0].script = `
let chatData = {whisper: ChatMessage.getWhisperRecipients("GM")}; let chatData = {whisper: ChatMessage.getWhisperRecipients("GM")};
let message = ""; 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 regenRoll = await new Roll("1d10").roll({allowInteractive : false});
let regen = regenRoll.total; let regen = regenRoll.total;
if (Blessures.value >= Blessures.max) if (wounds.value >= wounds.max)
return; return;
if (Blessures.value > 0) { if (wounds.value > 0) {
Blessures.value += Math.floor(regen / 2); wounds.value += Math.floor(regen / 2);
if (Blessures.value > Blessures.max) { if (wounds.value > wounds.max) {
Blessures.value = Blessures.max; wounds.value = wounds.max;
} }
message += \`<b>\${this.actor.name}</b> regagne \${regen} Blessures.\`; message += \`<b>\${this.actor.name}</b> regagne \${regen} Blessures.\`;
@@ -29,7 +29,7 @@ scriptData[0].script = `
} }
} else if (regen >= 8) { } else if (regen >= 8) {
message += \`<b>\${this.actor.name}</b> a obtenu un \${regen} et regagne 1 Blessure.\`; message += \`<b>\${this.actor.name}</b> a obtenu un \${regen} et regagne 1 Blessure.\`;
Blessures.value += 1; wounds.value += 1;
if (regen === 10) { if (regen === 10) {
message += "<br>De plus, il régénère une Blessure Critique."; 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.\`; 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")}); this.script.message(message, {whisper: ChatMessage.getWhisperRecipients("GM")});
` `
@@ -46,4 +46,4 @@ await effet.update({
"system.scriptData": scriptData "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é"}}) let test = await this.actor.setupCharacteristic("wp", {skipTargets: true, appendTitle : " - " + this.effect.name, context : {failure: "GAin d'1 état Sonné"}})
await Test.roll(); await test.roll();
if (Test.Échoué) if (test.failed)
{ {
this.actor.addCondition("stunned"); this.actor.addCondition("stunned");
} }

View File

@@ -22,7 +22,7 @@ let Test = await actor.setupSkill('Calme', {
fields: {difficulty: 'easy'}, fields: {difficulty: 'easy'},
characteristic: 'wp', characteristic: 'wp',
}); });
await Test.roll(); await test.roll();
if (!Test.succeeded) { if (!Test.succeeded) {
Test.result.other.push(`<b>${actor.name}</b> est devenu @Condition[Stunned] par la vue.`); 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); await this.actor.addEffectItems(bloodyFluxUUID, this.effet);
} else { } else {
const SL = Test.result.SL; const SL = test.result.SL;
const heal = 1 + SL; const heal = 1 + SL;
await this.actor.modifyWounds(heal); await this.actor.modifyWounds(heal);
this.script.message(`Butcher a soigné ${heal} Blessures.`); 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. // Imbibing this substance grants the user the Painless Creature Trait.
const hasutilisateur d = this.actor.has("Insensible à la douleur"); const hasPainless = this.actor.has("Insensible à la douleur");
if (hasutilisateur d === undefined) if (hasPainless === undefined)
{ {
let item = await fromUuid("Compendium.wfrp4e-core.items.wMwSRDmgiF2IdCJr"); let item = await fromUuid("Compendium.wfrp4e-core.items.wMwSRDmgiF2IdCJr");
let data = item.toObject() let data = item.toObject()
this.actor.createEmbeddedDocuments("Item", [data], {fromEffect: this.effect.id}) 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 `<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 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> 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"); args.actor.addCondition("poisoned");
const speaker = ChatMessage.getSpeaker({actor: args.actor}); 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>`); 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) if (args.test.result.SL < 0)
{ {
this.script.message(`Gain de ${Math.abs(args.test.result.SL)} Points de Corruption`, {whisper : ChatMessage.getWhisperRecipients("GM")}) 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)}) 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(); await test.roll();
if (Test.succeeded) { if (test.succeeded) {
let SL = parseInt(Test.result.SL); let SL = parseInt(test.result.SL);
let name = this.effect.name.replace(/\d+/, rating => parseInt(rating) - SL); let name = this.effect.name.replace(/\d+/, rating => parseInt(rating) - SL);
await this.effect.update({name}); 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"}}); 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).`); 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'}, fields: {difficulty: 'easy'},
characteristic: 'wp', characteristic: 'wp',
}); });
await Test.roll(); await test.roll();
if (!Test.succeeded) { 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.`); 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.script.notification("Ajout de A Terre");
this.actor.addCondition("prone") this.actor.addCondition("prone")

View File

@@ -1,6 +1,6 @@
let test = await this.actor.setupCharacteristic("wp", {skipTargets: true, appendTitle : ` - ${this.effect.name}`}) let test = await this.actor.setupCharacteristic("wp", {skipTargets: true, appendTitle : ` - ${this.effect.name}`})
await Test.roll(); await test.roll();
if (Test.succeeded) if (test.succeeded)
{ {
this.script.message("Peut réaliser une Action ou un Déplacement (choisissez-en un)") 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}`}) 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(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}`); 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.characteristicKey == "wp")
{ {
if (args.Test.Échoué) if (args.test.failed)
{ {
this.actor.addSystemEffect("convulsions") this.actor.addSystemEffect("convulsions")
this.script.message(`Test de FM échoué, <b>${this.actor.prototypeToken.name}</b> reçoit @Symptom[Convulsions] pour [[1d10]] heures`) 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 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 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") 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"}) 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}`}) let test = await this.actor.setupCharacteristic("wp", {skipTargets: true, appendTitle : ` - ${this.effect.name}`})
await Test.roll(); await test.roll();
if (Test.Échoué) if (test.failed)
{ {
this.script.message(await game.wfrp4e.tables.formatChatRoll("enrage-beast")) this.script.message(await game.wfrp4e.tables.formatChatRoll("enrage-beast"))
} }

View File

@@ -1,7 +1,7 @@
if (this.actor.Species.toLowerCase() != "skaven") { if (this.actor.Species.toLowerCase() != "skaven") {
this.actor.setupCharacteristic("t", {skipTargets: true, appendTitle : ` - Utilise ${this.effect.name}`, fields: { difficulty: "difficult" } }).then(async Test => { this.actor.setupCharacteristic("t", {skipTargets: true, appendTitle : ` - Utilise ${this.effect.name}`, fields: { difficulty: "difficult" } }).then(async Test => {
await Test.roll() await test.roll()
if (Test.Échoué) if (test.failed)
{ {
let toughnessLost = Math.ceil(CONFIG.Dice.randomUniform() * 10) let toughnessLost = Math.ceil(CONFIG.Dice.randomUniform() * 10)
this.actor.update({ "system.characteristics.t.initial": this.actor.characteristics.t.initial - toughnessLost }) 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}`}) let test = await this.actor.setupCharacteristic("wp", {fields: {difficulty : "average"}, skipTargets: true, appendTitle : ` - ${this.effect.name}`})
await Test.roll(); await test.roll();
if (Test.Échoué) 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) 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")) { 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}`}) let test = await this.actor.setupSkill(game.i18n.localize("NAME.Résistance"), {appendTitle : `- ${this.effect.name}`})
await Test.roll(); await test.roll();
if (Test.Échoué) if (test.failed)
{ {
let myRoll = await new Roll("1d10").roll({allowInteractive : false}); 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 regenRoll = await new Roll("1d10").roll({allowInteractive : false});
let regen = regenRoll.total; let regen = regenRoll.total;
if (Blessures.value >= Blessures.max) if (wounds.value >= wounds.max)
return return
if (Blessures.value > 0) if (wounds.value > 0)
{ {
Blessures.value += regen wounds.value += regen
if (Blessures.value > Blessures.max) if (wounds.value > wounds.max)
{ {
Blessures.value = Blessures.max wounds.value = wounds.max
} }
message += `<b>${this.actor.name}</b> regagne ${regen} Point de Blessures.` message += `<b>${this.actor.name}</b> regagne ${regen} Point de Blessures.`
@@ -25,7 +25,7 @@ if (Blessures.value > 0)
else if (regen >= 8) else if (regen >= 8)
{ {
message += `<b>${this.actor.name}</b> a fait un ${regen} et regagne 1 Point de Blessures.` 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) if (regen == 10)
{ {
message += `<br>De plus, il guérit d'une Blessure Critique.` 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.` 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") }) 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}`}); let test = await this.actor.setupSkill("Résistance", {fields : {difficulty : "difficult"}, appendTitle : ` - ${this.effect.name}`});
await Test.roll(); await test.roll();
if (Test.Échoué) if (test.failed)
{ {
await this.actor.addCondition("blinded"); 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}`}); 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'); 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" }}) let test = await this.actor.setupCharacteristic("ag", {skipTargets: true, appendTitle : ` - ${this.effect.name}`, context: { failure: "Goes Prone" }})
await Test.roll(); await test.roll();
if (Test.Échoué) if (test.failed)
{ {
this.actor.addCondition("prone"); 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é) { if (test.failed) {
const SL = Number(Test.result.SL); const SL = Number(test.result.SL);
this.script.message(`Butcher perd ${SL} dents.`); 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" 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"}) 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(); await test.roll();
if (Test.Échoué) if (test.failed)
{ {
this.actor.addCondition("dead"); this.actor.addCondition("dead");
} }

View File

@@ -7,8 +7,8 @@ let difficulty = ""
difficulty = "veasy" 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"}) 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(); await test.roll();
if (Test.Échoué) if (test.failed)
{ {
this.actor.addCondition("dead"); 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"}}) 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"); this.actor.addCondition("stunned");
} }

View File

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

View File

@@ -12,7 +12,7 @@ const test = await this.actor.setupCharacteristic("t", {
} }
}); });
await Test.roll(); await test.roll();
if (Test.failure) { if (test.failure) {
await this.actor.addCondition("prone"); 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}`}}); let test = await this.actor.setupSkill("Résistance", {fields : {difficulty : "difficult", appendTitle : ` - ${this.effect.name}`}});
await Test.roll(); await test.roll();
if (Test.Échoué) if (test.failed)
{ {
await this.actor.addCondition("blinded"); await this.actor.addCondition("blinded");
} }

View File

@@ -1,8 +1,8 @@
let test = await this.actor.setupCharacteristic("wp", {skipTargets: true, appendTitle : ` - ${this.effect.name}`}) 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") if (opposedResult?.winner == "attacker")
{ {

View File

@@ -1,7 +1,7 @@
let test = await this.actor.setupCharacteristic("t", { appendTitle: ` - ${this.effect.name}`, fields: { difficulty: "challenging" } }) 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 ageAdded = Math.ceil(CONFIG.Dice.randomUniform() * 10) + Math.ceil(CONFIG.Dice.randomUniform() * 10)
let ws = 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") 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}`}) let test = await this.actor.setupCharacteristic("wp", {skipTargets: true, appendTitle : ` - ${this.effect.name}`})
await Test.roll(); await test.roll();
// Kind of insane but whatever // 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"; return opposedResult?.winner == "attacker";

View File

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

View File

@@ -1,9 +1,9 @@
let location = this.item.system.location.key 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"}}) 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; let dropped = this.item.system.weaponsAtLocation;

View File

@@ -1,6 +1,6 @@
if (args.test.characteristicKey == "wp") if (args.test.characteristicKey == "wp")
{ {
if (args.Test.Échoué) if (args.test.failed)
{ {
this.actor.createEmbeddedDocuments("ActiveEffect", [game.wfrp4e.config.symptomEffects["malaise"]]) 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")}) 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}}) 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(); await test.roll();
if (Test.succeeded) if (test.succeeded)
{ {
this.script.notification(`Résistance à ${this.effect.name}`); this.script.notification(`Résistance à ${this.effect.name}`);
} }

View File

@@ -1,8 +1,8 @@
if (args.totalWoundLoss > 0) if (args.totalWoundLoss > 0)
{ {
args.actor.setupCharacteristic("t", {skipTargets: true, appendTitle : ` - ${this.effect.name}`, fields: { difficulty: "difficult" } }).then(async Test => { args.actor.setupCharacteristic("t", {skipTargets: true, appendTitle : ` - ${this.effect.name}`, fields: { difficulty: "difficult" } }).then(async Test => {
await Test.roll(); await test.roll();
if (Test.Échoué) if (test.failed)
{ {
await args.actor.addCondition("poisoned") await args.actor.addCondition("poisoned")
this.script.message(await args.actor.applyBasicDamage(3, {suppressMsg : true, damageType: game.wfrp4e.config.DAMAGE_TYPE.IGNORE_ALL })) 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"}}) let test = await this.actor.setupCharacteristic("t", {skipTargets: true, appendTitle : ` - ${this.effect.name}`, fields : {difficulty : "hard"}})
await Test.roll(); await test.roll();
if (Test.Échoué) if (test.failed)
{ {
let roll = await new Roll("1d10").roll({allowInteractive : false}); let roll = await new Roll("1d10").roll({allowInteractive : false});
roll.toMessage(this.script.getChatData()) roll.toMessage(this.script.getChatData())

Some files were not shown because too many files have changed in this diff Show More