516 lines
24 KiB
JavaScript
516 lines
24 KiB
JavaScript
/************************************************************************************/
|
|
import statParserFR from "./modules/import-stat-2.js";
|
|
|
|
/************************************************************************************/
|
|
var compmod = "wfrp4e";
|
|
const vo_conditions = {
|
|
"ablaze": "Ablaze",
|
|
"bleeding": "Bleeding",
|
|
"blinded": "Blinded",
|
|
"broken": "Broken",
|
|
"deafened": "Deafened",
|
|
"entangled": "Entangled",
|
|
"fatigued": "Fatigued",
|
|
"poisoned": "Poisoned",
|
|
"prone": "Prone",
|
|
"stunned": "Stunned",
|
|
"surprised": "Surprised",
|
|
"unconscious": "Unconscious",
|
|
"grappling": "Grappling",
|
|
"fear": "Fear",
|
|
"defeated": "Defeated"
|
|
}
|
|
|
|
/************************************************************************************/
|
|
Hooks.once('init', () => {
|
|
|
|
// Check various settings in the installation
|
|
game.modules.forEach((module, name) => {
|
|
if ( name == "wfrp4e-core" && module.active) {
|
|
compmod = "wfrp4e-core";
|
|
}
|
|
} );
|
|
game.wfrp4efr = { compmod: compmod,
|
|
vo_conditions: vo_conditions }
|
|
|
|
game.wfrp4e.apps.StatBlockParser.parseStatBlock = async function( statString, type = "npc") {
|
|
return statParserFR( statString, type);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
game.wfrp4e.entities.ItemWfrp4e.prototype.computeSpellDamage = function(formula, isMagicMissile) {
|
|
try {
|
|
|
|
formula = formula.toLowerCase();
|
|
|
|
if (isMagicMissile) // If it's a magic missile, damage includes willpower bonus
|
|
{
|
|
formula += "+ " + this.actor.characteristics["wp"].bonus
|
|
}
|
|
|
|
// Specific case, to avoid wrong matching with "Force"
|
|
if (formula.includes("toughness bonus")) {
|
|
formula = formula.replace( "toughness bonus", this.actor.characteristics["t"].bonus);
|
|
}
|
|
|
|
// Specific case, to avoid wrong matching with "Force"
|
|
if (formula.includes("force mentale"))
|
|
{
|
|
// Determine if it's looking for the bonus or the value
|
|
if (formula.includes('bonus')) {
|
|
formula = formula.replace( "bonus de force mentale", this.actor.characteristics["wp"].bonus);
|
|
formula = formula.replace( "force mentale bonus", this.actor.characteristics["wp"].bonus);
|
|
} else
|
|
formula = formula.replace("force mentale", this.actor.characteristics["wp"].value);
|
|
}
|
|
|
|
// Iterate through characteristics
|
|
for(let ch in this.actor.characteristics)
|
|
{
|
|
// If formula includes characteristic name
|
|
while (formula.includes(this.actor.characteristics[ch].label.toLowerCase()))
|
|
{
|
|
// Determine if it's looking for the bonus or the value
|
|
if (formula.includes('bonus')) {
|
|
formula = formula.replace("bonus de " + game.wfrp4e.config.characteristics[ch].toLowerCase(), this.actor.characteristics[ch].bonus);
|
|
formula = formula.replace(game.wfrp4e.config.characteristics[ch].toLowerCase() + " bonus", this.actor.characteristics[ch].bonus);
|
|
}
|
|
else
|
|
formula = formula.replace(game.wfrp4e.config.characteristics[ch].toLowerCase(), this.actor.characteristics[ch].value);
|
|
}
|
|
}
|
|
|
|
return eval(formula);
|
|
}
|
|
catch (e) {
|
|
throw ui.notifications.error("Error: could not parse spell damage. See console for details")
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
game.wfrp4e.entities.ItemWfrp4e.prototype.computeSpellPrayerFormula = function(type, aoe=false, formulaOverride) {
|
|
let formula = formulaOverride || this[type]?.value
|
|
if (Number.isNumeric(formula))
|
|
return formula
|
|
|
|
//console.log("Compute FR")
|
|
formula = formula.toLowerCase();
|
|
|
|
// Do not process these special values
|
|
if (formula != game.i18n.localize("You").toLowerCase() && formula != game.i18n.localize("Special").toLowerCase() && formula != game.i18n.localize("Instant").toLowerCase())
|
|
{
|
|
// Specific case, to avoid wrong matching with "Force"
|
|
if (formula.includes("force mentale"))
|
|
{
|
|
// Determine if it's looking for the bonus or the value
|
|
if (formula.includes('bonus')) {
|
|
formula = formula.replace( "bonus de force mentale", this.actor.characteristics["wp"].bonus);
|
|
formula = formula.replace( "force mentale bonus", this.actor.characteristics["wp"].bonus);
|
|
}
|
|
else
|
|
formula = formula.replace("force mentale", this.actor.characteristics["wp"].value);
|
|
}
|
|
if (formula.includes("yard") )
|
|
formula = formula.replace('yard', "mètre" );
|
|
if (formula.includes("yds") )
|
|
formula = formula.replace('yds', "m." );
|
|
// Iterate through remaining characteristics
|
|
for(let ch in this.actor.characteristics)
|
|
{
|
|
// If formula includes characteristic name
|
|
//console.log("Testing :", ch, WFRP4E.characteristics[ch].toLowerCase());
|
|
if (formula.includes(game.wfrp4e.config.characteristics[ch].toLowerCase()))
|
|
{
|
|
// Determine if it's looking for the bonus or the value
|
|
if (formula.includes('bonus')) {
|
|
formula = formula.replace("bonus de " + game.wfrp4e.config.characteristics[ch].toLowerCase(), this.actor.characteristics[ch].bonus);
|
|
formula = formula.replace(game.wfrp4e.config.characteristics[ch].toLowerCase() + " bonus", this.actor.characteristics[ch].bonus);
|
|
}
|
|
else
|
|
formula = formula.replace(game.wfrp4e.config.characteristics[ch].toLowerCase(), this.actor.characteristics[ch].value);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If AoE - wrap with AoE ( )
|
|
if (aoe)
|
|
formula = "AoE (" + formula.capitalize() + ")";
|
|
|
|
//console.log("calculateSpellAttributes -> " + formula );
|
|
return formula.capitalize();
|
|
}
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
// Converters area
|
|
if(typeof Babele !== 'undefined') {
|
|
|
|
Babele.get().register({
|
|
module: 'WH4-fr-translation',
|
|
lang: 'fr',
|
|
dir: 'compendium'
|
|
});
|
|
|
|
Babele.get().registerConverters({
|
|
|
|
"career_skills": (skills_list) => {
|
|
//console.log( "Thru here ...", compendium, skills_list);
|
|
if ( skills_list ) {
|
|
var i;
|
|
var len = skills_list.length;
|
|
var re = /(.*)\((.*)\)/i;
|
|
for (i = 0; i < len; i++) {
|
|
skills_list[i] = skills_list[i].trim();
|
|
var transl = game.babele.translate(compmod+'.skills', { name: skills_list[i] }, true ).name;
|
|
//console.log("List ...", skills_list[i]);
|
|
if ( transl == skills_list[i] ) {
|
|
var res = re.exec( skills_list[i] );
|
|
if (res) {
|
|
//console.log("Matched/split:", res[1], res[2]);
|
|
var subword = game.i18n.localize(res[2].trim() );
|
|
var s1 = res[1].trim() + " ()";
|
|
var translw = game.babele.translate(compmod+'.skills', { name: s1}, true ).name;
|
|
if (translw != s1) {
|
|
var res2 = re.exec(translw);
|
|
transl = res2[1] + "(" + subword + ")";
|
|
} else {
|
|
s1 = res[1].trim() + " ( )";
|
|
translw = game.babele.translate(compmod+'.skills', { name: s1}, true ).name;
|
|
var res2 = re.exec(translw);
|
|
transl = res2[1] + "(" + subword + ")";
|
|
}
|
|
}
|
|
}
|
|
skills_list[i] = transl;
|
|
}
|
|
}
|
|
return skills_list;
|
|
},
|
|
|
|
"npc_details": (details) => {
|
|
//console.log("DETAILS: ", details);
|
|
let newDetails = duplicate(details);
|
|
if (details.species && details.species.value )
|
|
newDetails.species.value = game.i18n.localize(details.species.value);
|
|
if (details.gender && details.gender.value )
|
|
newDetails.gender.value = game.i18n.localize(details.gender.value);
|
|
if (details.class && details.class.value )
|
|
newDetails.class.value = game.i18n.localize(details.class.value);
|
|
return newDetails;
|
|
},
|
|
|
|
"career_talents": (talents_list) => {
|
|
var compendium = game.packs.find(p => p.collection === compmod+'.talents');
|
|
var i;
|
|
if ( talents_list ) {
|
|
var len = talents_list.length;
|
|
var re = /(.*)\((.*)\)/i;
|
|
for (i = 0; i < len; i++) {
|
|
var transl = game.babele.translate(compmod+'.talents', { name: talents_list[i]}, true ).name;
|
|
if ( transl == talents_list[i] ) {
|
|
var res = re.exec( talents_list[i]);
|
|
if (res) {
|
|
//console.log("Matched/split:", res[1], res[2]);
|
|
var subword = game.i18n.localize(res[2].trim() );
|
|
var s1 = res[1].trim(); // No () in talents table
|
|
var translw = game.babele.translate(compmod+'.talents', { name: s1 }, true ).name;
|
|
if (translw != s1) {
|
|
transl = translw + " (" + subword + ")";
|
|
} else {
|
|
s1 = res[1].trim() + " ( )";
|
|
translw = game.babele.translate(compmod+'.talents', { name: s1 }, true ).name;
|
|
var res2 = re.exec(translw);
|
|
transl = res2[1] + " (" + subword + ")";
|
|
}
|
|
}
|
|
}
|
|
talents_list[i] = transl;
|
|
}
|
|
}
|
|
return talents_list;
|
|
},
|
|
"npc_characteristics": (chars) => { // Auto-convert char names in the sheet
|
|
for (var key in chars) {
|
|
var char = chars[key];
|
|
//console.log("Was here !", key, char );
|
|
var abrev = char["abrev"];
|
|
let toTransl = "CHAR." + abrev;
|
|
if ( game.i18n.localize( toTransl ) != toTransl) { // Manages unknown language
|
|
char["label"] = game.i18n.localize( "CHAR." + abrev );
|
|
char["abrev"] = game.i18n.localize( "CHARAbbrev." + abrev );
|
|
}
|
|
}
|
|
return chars;
|
|
},
|
|
"bestiary_traits": (beast_traits, translations) => {
|
|
|
|
for (let trait_en of beast_traits)
|
|
{
|
|
var special = "";
|
|
var nbt = "";
|
|
var name_en = trait_en.name.trim(); // strip \r in some traits name
|
|
|
|
if ( trait_en.type == "trait") {
|
|
if ( name_en.includes("Tentacles") ) { // Process specific Tentacles case
|
|
var re = /(.d*)x Tentacles/i;
|
|
var res = re.exec( name_en );
|
|
if ( res && res[1] )
|
|
nbt = res[1] + "x ";
|
|
name_en = "Tentacles";
|
|
} else if ( name_en.includes("(") && name_en.includes(")") ) { // Then process specific traits name with (xxxx) inside
|
|
var re = /(.*) \((.*)\)/i;
|
|
var res = re.exec( name_en );
|
|
name_en = res[1]; // Get the root traits name
|
|
special = " (" + game.i18n.localize( res[2].trim() ) + ")"; // And the special keyword
|
|
}
|
|
var trait_fr = game.babele.translate( compmod+'.traits', { name: name_en }, true );
|
|
//console.log(">>>>> Trait ?", name_en, nbt, trait_fr, trait_fr.name, special);
|
|
trait_en.name = nbt + trait_fr.name + special;
|
|
if ( trait_fr.data && trait_fr.data.description && trait_fr.data.description.value ) {
|
|
trait_en.data.description.value = trait_fr.data.description.value;
|
|
} else if ( game.modules.get( 'wfrp4e-eis') ) { // No description in the FR compendium -> test other compendium if presenr
|
|
trait_fr = game.babele.translate( 'wfrp4e-eis.eisitems', { name: name_en }, true);
|
|
trait_en.name = nbt + trait_fr.name + special;
|
|
if ( trait_fr.data && trait_fr.data.description && trait_fr.data.description.value )
|
|
trait_en.data.description.value = trait_fr.data.description.value;
|
|
}
|
|
if ( trait_en.data && trait_en.data.specification && isNaN(trait_en.data.specification.value) ) { // This is a string, so translate it
|
|
//console.log("Translating : ", trait_en.data.specification.value);
|
|
trait_en.data.specification.value = game.i18n.localize( trait_en.data.specification.value.trim() );
|
|
}
|
|
} else if ( trait_en.type == "skill") {
|
|
if ( name_en.includes("(") && name_en.includes(")") ) { // Then process specific skills name with (xxxx) inside
|
|
var re = /(.*) +\((.*)\)/i;
|
|
var res = re.exec( name_en );
|
|
name_en = res[1].trim(); // Get the root skill name
|
|
special = " (" + game.i18n.localize( res[2].trim() ) + ")"; // And the special keyword
|
|
}
|
|
var trait_fr = game.babele.translate( compmod+'.skills', { name: name_en }, true );
|
|
//console.log(">>>>> Skill ?", name_en, special, trait_fr.name, trait_fr);
|
|
if (trait_fr.name != name_en) { // Translation OK
|
|
trait_en.name = trait_fr.name + special;
|
|
if ( trait_fr.data ) {
|
|
trait_en.data.description.value = trait_fr.data.description.value;
|
|
}
|
|
}
|
|
|
|
} else if ( trait_en.type == "prayer") {
|
|
var trait_fr = game.babele.translate( compmod+'.prayers', { name: name_en }, true);
|
|
//console.log(">>>>> Prayer ?", name_en, special, trait_fr.name );
|
|
trait_en.name = trait_fr.name + special;
|
|
if ( trait_fr.data && trait_fr.data.description && trait_fr.data.description.value )
|
|
trait_en.data.description.value = trait_fr.data.description.value;
|
|
|
|
} else if ( trait_en.type == "spell") {
|
|
var trait_fr = game.babele.translate( compmod+'.spells', { name: name_en }, true);
|
|
if ( trait_fr.name == name_en ) { // If no translation, test eisspells
|
|
trait_fr = game.babele.translate( 'wfrp4e-eis.eisspells', { name: name_en }, true);
|
|
}
|
|
if ( trait_fr.name == name_en ) { // If no translation, test unofficial grimoire
|
|
trait_fr = game.babele.translate( 'wfrp4e-unofficial-grimoire.ug-spells', { name: name_en }, true);
|
|
}
|
|
//console.log(">>>>> Spell ?", name_en, special, trait_fr.name );
|
|
trait_en.name = trait_fr.name + special;
|
|
if ( trait_fr.data && trait_fr.data.description && trait_fr.data.description.value )
|
|
trait_en.data.description.value = trait_fr.data.description.value;
|
|
} else if ( trait_en.type == "talent") {
|
|
if ( name_en.includes("(") && name_en.includes(")") ) { // Then process specific skills name with (xxxx) inside
|
|
var re = /(.*) +\((.*)\)/i;
|
|
var res = re.exec( name_en );
|
|
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
|
|
}
|
|
var trait_fr = game.babele.translate( compmod+'.talents', { name: name_en }, true );
|
|
//console.log(">>>>> Talent ?", trait_fr, name_en, special, trait_fr.name);
|
|
if ( trait_fr.name != "Sprinter" && trait_fr.name == name_en) { // If no translation, test ugtalents
|
|
trait_fr = game.babele.translate( 'wfrp4e-unofficial-grimoire.ug-careerstalentstraits', { name: name_en }, true );
|
|
}
|
|
if ( trait_fr.name == "Sprinter" || trait_fr.name != name_en) { // Talent translated!
|
|
trait_en.name = trait_fr.name.trim() + special;
|
|
if ( trait_fr.data ) { // Why ???
|
|
trait_en.data.description.value = trait_fr.data.description.value;
|
|
}
|
|
}
|
|
} else if ( trait_en.type == "career") {
|
|
var career_fr = game.babele.translate( compmod+'.careers', trait_en, true );
|
|
console.log(">>>>> Career ?", name_en, career_fr.name );
|
|
trait_en.name = career_fr.name;
|
|
trait_en.data = duplicate(career_fr.data);
|
|
} else if ( trait_en.type == "trapping" || trait_en.type == "weapon" || trait_en.type == "armour" || trait_en.type == "container" || trait_en.type == "money") {
|
|
var trapping_fr = game.babele.translate( compmod+'.trappings', trait_en, true );
|
|
//console.log(">>>>> Trapping ?", name_en, trapping_fr.name);
|
|
trait_en.name = trapping_fr.name;
|
|
if ( trapping_fr.data) {
|
|
trait_en.data.description = trapping_fr.data.description;
|
|
}
|
|
}
|
|
}
|
|
return beast_traits;
|
|
},
|
|
// To avoid duplicateing class for all careers
|
|
"generic_localization": (value) => {
|
|
if ( value )
|
|
return game.i18n.localize( value.trim() );
|
|
},
|
|
"trapping_qualities_flaws": (value) => {
|
|
if ( value ) {
|
|
let newQF = [];
|
|
//console.log("ATOUTS", value);
|
|
var i=0;
|
|
//var re = /(.*) (\d+)/i;
|
|
for (i=0; i<value.length; i++) {
|
|
newQF[i] = duplicate(value[i]);
|
|
if ( newQF[i].name == "Trap Blade") {
|
|
newQF[i].name = "TrapBlade"; // Auto-patch, without space!
|
|
//console.log("PATCHED", trim);
|
|
}
|
|
newQF[i].name = game.i18n.localize( newQF[i].name ) ;
|
|
}
|
|
return newQF;
|
|
}
|
|
},
|
|
// Search back in careers the translated name of the groupe (as it is the name of the level career itself)
|
|
"career_careergroup": (value) => {
|
|
// Manage exception - Dirty hack
|
|
if ( value == 'Slayer' ) {
|
|
return "Tueur";
|
|
}
|
|
if ( value == 'Druidic Priest' ) {
|
|
return "Druide";
|
|
}
|
|
// Per default
|
|
var compendium = game.packs.find(p => p.collection === compmod+'.careers');
|
|
if ( compendium )
|
|
return game.babele.translate(compmod+'.careers', { name: value } ).name;
|
|
else
|
|
ui.notifications.error("Impossible de trouver la carrière " + value + ". Elle n'est probablement pas traduite.", { permanent: true })
|
|
},
|
|
"mutations_modifier": (value) => { // This is really UGLYYYY i know, but i started like this and discovered afterward that many strings were not easy to automate... Sorry :)
|
|
//console.log("Parsing mutation :", value);
|
|
value = value.toLowerCase();
|
|
value = value.replace("gain a broken condition if you fail a test derived from ", "Gagnez un état Brisé si vous échouez à un test dérivé de ");
|
|
value = value.replace("weapon skill" ,"Capacité de Combat");
|
|
value = value.replace("ballistic skill", "Capacité de Tir");
|
|
value = value.replace("strength", "Force");
|
|
value = value.replace("toughness", "Endurance");
|
|
value = value.replace("agility", "Agilité");
|
|
value = value.replace("dexterity", "Dextérité");
|
|
value = value.replace("willpower", "Force Mentale");
|
|
value = value.replace("fellowship", "Sociabilité");
|
|
value = value.replace("initiative", "Initiative");
|
|
value = value.replace("intelligence", "Intelligence");
|
|
value = value.replace("armor points to the head", "PA à la Tête");
|
|
value = value.replace("subject to frenzy", "Sujet à la Frénésie");
|
|
value = value.replace("you do not scar", "Aucune cicatrice");
|
|
value = value.replace("movement", "Mouvement");
|
|
value = value.replace("armor points to all locations", "PA sur tout le corps");
|
|
value = value.replace("to any test when alone", "à tout les tests lorsque seul");
|
|
value = value.replace("track", "Pistage");
|
|
value = value.replace("to any test not hurting another", "à tout les Tests n'aggressant pas autrui");
|
|
value = value.replace("on tests to hurt", "pour les tests impliquant une agression")
|
|
value = value.replace("to all language tests when speaking", "à tout les Tests de Langue lorsque vous parlez");
|
|
value = value.replace("on perception tests involving sight", "aux Tests de Perception impliquant la Vue");
|
|
value = value.replace("to all Sociabilité tests", "à tout les Tests de Sociabilité");
|
|
return value;
|
|
},
|
|
"talent_name": (name, translation) => {
|
|
console.log("NAME !!!", name, translation);
|
|
},
|
|
"effects": (effects, translations) => {
|
|
if ( !effects) return;
|
|
if ( !translations) return;
|
|
for (let i=0; i<effects.length; i++) {
|
|
let effect = effects[i];
|
|
//console.log("EFFECT LABEL1:", effect );
|
|
effect.label = translations['label'+i];
|
|
}
|
|
return effects
|
|
},
|
|
"diseases_effects": (effects, translations) => {
|
|
if ( !effects) return;
|
|
for (let i=0; i<effects.length; i++) {
|
|
let effect = effects[i];
|
|
let label = effect.label;
|
|
let gravity = "";
|
|
if ( label.includes("(") && label.includes(")") ) { // Then process specific skills name with (xxxx) inside
|
|
var re = /(.*) +\((.*)\)/i;
|
|
var res = re.exec( label );
|
|
label = res[1].trim(); // Get the gravity
|
|
gravity = " (" + game.i18n.localize( res[2].trim() ) + ")"; // And the special keyword
|
|
}
|
|
effect.label = game.i18n.localize( label ) + gravity;
|
|
}
|
|
},
|
|
// Auto-translate duration
|
|
"spells_duration_range_target_damage": (value) => {
|
|
//console.log("Spell duration/range/damage/target :", value);
|
|
if ( value == "" ) return ""; // Hop !
|
|
if ( value == "Touch" ) return "Contact"; // Hop !
|
|
if ( value == "You" ) return "Vous"; // Hop !
|
|
if ( value == "Instant" ) return "Instantané"; // Hop !
|
|
var translw = value;
|
|
var re = /(.*) Bonus (\w*)/i;
|
|
var res = re.exec( value );
|
|
var unit = "";
|
|
if ( res ) { // Test "<charac> Bonus <unit>" pattern
|
|
if ( res[1] ) { // We have char name, then convert it
|
|
translw = "Bonus de " + game.i18n.localize( res[1].trim() );
|
|
}
|
|
unit = res[2];
|
|
} else {
|
|
re = /(\d+) (\w+)/i;
|
|
res = re.exec( value );
|
|
if (res) { // Test : "<number> <unit>" pattern
|
|
translw = res[1];
|
|
unit = res[2];
|
|
} else { // Test
|
|
re = /(\w+) (\w+)/i;
|
|
res = re.exec( value );
|
|
if (res) { // Test : "<charac> <unit>" pattern
|
|
translw = game.i18n.localize( res[1].trim() );
|
|
unit = res[2];
|
|
}
|
|
}
|
|
}
|
|
if ( unit == "hour") unit = "heure";
|
|
if ( unit == "hours") unit = "heures";
|
|
if ( unit == "days") unit = "jours";
|
|
if ( unit == "yard") unit = "mètre";
|
|
if ( unit == "yards") unit = "mètres";
|
|
translw += " " + unit;
|
|
return translw;
|
|
}
|
|
});
|
|
}
|
|
|
|
} );
|
|
|
|
/* -------------------------------------------- */
|
|
// Register world usage statistics
|
|
function registerUsageCount( registerKey ) {
|
|
if ( game.user.isGM ) {
|
|
game.settings.register(registerKey, "world-key", {
|
|
name: "Unique world key",
|
|
scope: "world",
|
|
config: false,
|
|
default: "",
|
|
type: String
|
|
});
|
|
|
|
let worldKey = game.settings.get(registerKey, "world-key")
|
|
if ( worldKey == undefined || worldKey == "" ) {
|
|
worldKey = randomID(32)
|
|
game.settings.set(registerKey, "world-key", worldKey )
|
|
}
|
|
// Simple API counter
|
|
let regURL = `https://www.uberwald.me/fvtt_appcount/count.php?name="${registerKey}"&worldKey="${worldKey}"&version="${game.release.generation}.${game.release.build}"&system="${game.system.id}"&systemversion="${game.system.version}"`
|
|
$.ajax(regURL)
|
|
/* -------------------------------------------- */
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
Hooks.once('ready', () => {
|
|
|
|
registerUsageCount("wh4-fr-translation")
|
|
|
|
}); |