Auto-patch skill and swid

This commit is contained in:
LeRatierBretonnien 2023-10-20 22:25:59 +02:00
parent 2dab24eaa0
commit b5ec752537
15 changed files with 171 additions and 18 deletions

View File

@ -3,7 +3,7 @@
"mapping": {
"description": "system.description",
"skill": {
"path": "system.actions.skill",
"path": "system.actions.trait",
"converter": "gear_skill"
},
"range": {

View File

@ -3,7 +3,7 @@
"mapping": {
"description": "system.description",
"skill": {
"path": "system.actions.skill",
"path": "system.actions.trait",
"converter": "gear_skill"
},
"range": {

View File

@ -3,7 +3,7 @@
"mapping": {
"description": "system.description",
"skill": {
"path": "system.actions.skill",
"path": "system.actions.trait",
"converter": "gear_skill"
},
"range": {

View File

@ -3,7 +3,7 @@
"mapping": {
"description": "system.description",
"skill": {
"path": "system.actions.skill",
"path": "system.actions.trait",
"converter": "gear_skill"
},
"range": {

View File

@ -3,7 +3,7 @@
"mapping": {
"description": "system.description",
"skill": {
"path": "system.actions.skill",
"path": "system.actions.trait",
"converter": "gear_skill"
},
"range": {

View File

@ -3,7 +3,7 @@
"mapping": {
"description": "system.description",
"skill": {
"path": "system.actions.skill",
"path": "system.actions.trait",
"converter": "gear_skill"
},
"range": {

View File

@ -3,7 +3,7 @@
"mapping": {
"description": "system.description",
"skill": {
"path": "system.actions.skill",
"path": "system.actions.trait",
"converter": "gear_skill"
},
"range": {

View File

@ -3,7 +3,7 @@
"mapping": {
"description": "system.description",
"skill": {
"path": "system.actions.skill",
"path": "system.actions.trait",
"converter": "gear_skill"
},
"range": {

View File

@ -3,7 +3,7 @@
"mapping": {
"description": "system.description",
"skill": {
"path": "system.actions.skill",
"path": "system.actions.trait",
"converter": "gear_skill"
},
"range": {

View File

@ -3,7 +3,7 @@
"mapping": {
"description": "system.description",
"skill": {
"path": "system.actions.skill",
"path": "system.actions.trait",
"converter": "gear_skill"
},
"range": {

View File

@ -1,7 +1,11 @@
{
"label": "SWADE Compétences",
"mapping": {
"description_full": "system.description"
"description_full": "system.description",
"swid": {
"path": "system.swid",
"converter": "skill_swid"
}
},
"entries": [
{

View File

@ -3,7 +3,7 @@
"mapping": {
"description": "system.description",
"skill": {
"path": "system.actions.skill",
"path": "system.actions.trait",
"converter": "gear_skill"
},
"range": {

View File

@ -57,7 +57,7 @@
}
],
"url": "https://www.uberwald.me/gitea/public/swade-fr-content",
"version": "3.0.2",
"version": "3.2.0",
"esmodules": [
"modules/swade-fr-init.js"
],
@ -73,14 +73,13 @@
}
],
"manifest": "https://www.uberwald.me/gitea/public/swade-fr-content/raw/branch/master/module.json",
"download": "https://www.uberwald.me/gitea/public/swade-fr-content/archive/swade-fr-content-3.0.2.zip",
"download": "https://www.uberwald.me/gitea/public/swade-fr-content/archive/swade-fr-content-3.2.0.zip",
"id": "swade-fr-content",
"relationships": {
"requires": [
{
"id": "babele",
"type": "module",
"manifest": "https://gitlab.com/riccisi/foundryvtt-babele/raw/master/module/module.json",
"compatibility": {}
}
],

View File

@ -0,0 +1,116 @@
const actorText = "OISEAU-TONNERRE\nCe sont les gardiens des Terres de chasse.Ils sont pra - tiquement aussi omniscients que tu pourrais lêtre sans être le Créateur lui - même.Quatre grands oiseaux - ton - nerre anciens habitent quelque part dans le monde des esprits, mais on ne peut jamais les rencontrer, à moins quils ne le veuillent.Les caractéristiques disponibles ici sappliquent aux oiseaux - tonnerre plus jeunes qui volent haut dans le ciel des Terres de chasse.Ces créatures ont lapparence dimmenses et puissants oiseaux de proie, dune majesté absolument terrifiante.Et pourtant, ces gardiens sont lunique raison qui a empêché les mani - tous de prendre le contrôle total du monde des esprits.Les oiseaux - tonnerre ont tendance à être lunatiques et imprévisibles.\nAllure: 8(dé de course d10) Charisme: 0 Trempe: 2\n" +
"TRAITS\n" +
"Agi Âme For Int Vig d10 d8 d10 d6 d8 Compétences : Combat d10, Discrétion d8, Équi- tation d10, Intimidation d8, Pistage d8, Survie d6, Tir d10, Tripes d8. Handicaps : Serment des Anciennes Traditions (Majeur), Têtu. Atouts : Blocage, Esprit totem (variable), Véloce.\nDÉFENSE Parade Résistance 8 7 CAPACITÉS SPÉCIALES Arcane : Chamanisme, Médecine tribale d10, PP 25. Don (étoile filante) : au début dun combat, peut dépen- ser 1 Jeton pour augmenter la portée de ses Atouts de Commandement jusquà la fin du combat. Blanc : +Âme ; rouge : +Âme × 2 ; bleu : +Âme × 3. Esprit totem (chouette) : le coût en PP du pouvoir Ter- reur est divisé par 2 si Relance de Médecine tribale. Esquive : inflige -1 aux attaques à distance. Inspiration : +2 pour annuler Secoué pour les alliés dans un rayon de 5 cases. Leader naturel : peut donner des Jetons aux alliés dans un rayon de 5 cases. Tête froide : agit sur la meilleure de deux cartes dInitiative. Volonté de fer : Intimidation +2, Sarcasme +2, y résister +2.\nACTIONS\nArmure : Médecine tribale d10, PP 2, T, Durée 3 (1/rd), +2 en Armure, -4 avec une Relance. Arc : Tir d10, 2d6, 12/24/48, CdT 1, Munitions 1, 20 flèches. Augmentation/Diminution de Trait : Médecine tri- bale d10, PP 2, Int, Durée 3 (1/rd), +/-1 au type de dé dans un Trait (+/-2 en cas de Relance). Bâton de coup de Crazy Horse : voir p. 66. Pioche un Je- ton la première fois quil touche un adversaire dange- reux, Marque le coup (nécessite Attaque pour toucher, que sur adversaire armé, conscient et dangereux, une seule fois, sans dégâts). Couteau : Combat d12, d10+d4, PA 1. Déflexion: Médecine tribale d10, PP 2, T, Durée 3 (1/rd), -2 pour toucher le sujet, -4 avec une Relance. Frappe : Médecine tribale d10, PP 2, T, Durée 3 (1 / Round), +2 de dégâts sur une arme, +4 avec Relance. Frénésie suprême : peut faire une attaque en Combat supplémentaire. Guérison : Médecine tribale d10, PP 3, T, Durée Inst., soigne une Blessure vieille de moins d1 h. Masse de guerre à lame : Combat d12, d10+d8, PA 2, Parade -1, Maniement à deux mains. Poigne ferme : ignore la pénalité de Plateforme instable. Terreur : Médecine tribale d10, PP 2, Int × 2, Durée Inst., jet de Tripes pour cibles dans GG (-2 si Relance), Ex- tras paniqués, Jokers tirent sur la Table de Terreur. Tireur délite : Tir +2 si pas de mouvement (Visée).Visée : Médecine tribale d10, PP 1, T, Durée 3 (1/rd), pé- nalité dattaque ciblée réduite de 1 (2 sur Relance).\nÉQUIPEMENT Sac médecine, cheval.";
const __attrMapping = {agility: 0, spirit: 1, smarts: 3, vigor:4, strength: 2 }
export class SWDELUXStatBlockParser {
constructor() {
this.parsingTable = {
attributs: { regex: /TRAITS\s*(.*?)\s*Comp/, value: "", attributs: {}, elements: [] },
competences: { regex: /Compétences\s*:\s*(.*?).\s+Handicaps/, value: "", elements: [] },
atouts: { regex: /Atouts\s*:\s*(.*?).\s*DÉFENSE/, value: "", elements: [] },
handicaps: { regex: /Handicaps\s*:\s*(.*?).\s+Atouts/, value: "", elements: [] },
defense: { regex: /nDÉFENSE\s*Parade\s*Résistance\s+(\d+)\s+(\d+)/, parade: 0, resistance: 0 },
capacites: { regex: /CAPACITÉS SPÉCIALES\s*(.*?)\s*ACTIONS|ÉQUIPEMENT|$/, value: "", elements: [] },
actions: { regex: /ACTIONS\s*(.*?)\s*ÉQUIPEMENT|$/, value: "", elements: [] },
equipement: { regex: /ÉQUIPEMENT\s*(.*)$/, value: "", elements: [] }
}
console.log("MODEL", this.model)
}
async parse(actorText) {
let parsingTable = this.parsingTable; // Shortcut
// Cleanup phase and format stat block
let splitted = actorText.split("Allure");
let charDesc = splitted[0]
let statBlock = "Allure : " + splitted[1]
let charName = charDesc.split("\n")[0]
statBlock = statBlock.replace(/\n/g, ' ');
statBlock = statBlock.replace(/- /g, '');
// Add missing section headers, needed to easily parse the stat block
if (!statBlock.includes('CAPACITÉS SPÉCIALES')) {
statBlock += "\nCAPACITÉS SPÉCIALES : ";
}
if (!statBlock.includes('ACTIONS')) {
statBlock += "\nACTIONS : ";
}
if (!statBlock.includes('ÉQUIPEMENT')) {
statBlock += "\nÉQUIPEMENT : ";
}
for (let key in parsingTable) {
let parseData = parsingTable[key]
parseData.key = key;
let match = parseData.regex.exec(statBlock)
//console.log("MATCH", key, match);
if (match && match[1]) {
if (key == "attributs") {
const diceSide = match[1].match(/\d+/g);
parseData.traitMatch = diceSide
console.log("TRAITMATCH", parseData.traitMatch);
}
if (parseData.value == "") {
parseData.value = match[1]
}
if (key == "competences") {
// Utiliser une expression régulière pour extraire chaque compétence et sa valeur de dé
const regex = /([\w\séèàÉ'()-]+)\s+(d\d+)\s*,\s*/g;
let skillDef;
while ((skillDef = regex.exec(match[1])) !== null) {
const skill = skillDef[1].trim();
const value = skillDef[2];
parseData.elements.push({ name: skill, dice: value });
}
console.log("SKILLS", parseData.skills);
}
if (key == "atouts" || key == "handicaps") {
const regex = /([\w\séèàÉ'()-]+)\s*,\s*/g;
let elemDef;
while ((elemDef = regex.exec(match[1])) !== null) {
const name = elemDef[1].trim();
parseData.elements.push({ name });
}
}
if (key == "capacites" || key == "actions") {
const regex = /([\w\séèàÉ'()-]+)\s*:\s*([\w\séèàÉ\d,'()-]+)\s*./g;
let elemDef;
while ((elemDef = regex.exec(match[1])) !== null) {
const name = elemDef[1].trim();
const text = elemDef[2].trim();
parseData.elements.push({ name, text });
}
}
if (key == "equipement") {
const regex = /([\w\séèàÉ$\d'()-]+)\s*[,|.]\s*/g;
let elemDef;
while ((elemDef = regex.exec(match[1])) !== null) {
const name = elemDef[1].trim();
parseData.elements.push({ name });
}
}
if (key == "defense") {
parseData.parade = match[1];
parseData.resistance = match[2];
}
console.log("PARSED", parseData);
}
}
let actor = await Actor.create({name: charName || "PNJ importé", type: "npc", items: []})
let updates = {}
for (let key in __attrMapping) {
let index = __attrMapping[key]
updates[`system.attributes.${key}.die.sides`] = Number(this.parsingTable["attributs"].traitMatch[index])
}
actor.update( updates )
console.log("ACTOR", actor, updates);
}
}

View File

@ -1,3 +1,4 @@
import { SWDELUXStatBlockParser } from "./sw-statblock-parser.js";
const __compFolderTranslation = [
{
@ -68,6 +69,7 @@ class swadeFrTranslator {
/************************************************************************************/
Hooks.once('init', () => {
console.log("INIT !!!!!!")
if (typeof Babele !== 'undefined') {
console.log("BABELE LOADED !!!");
@ -80,12 +82,18 @@ Hooks.once('init', () => {
Babele.get().registerConverters({
"gear_skill": (skill) => {
let transl = skill
//console.log("Testing", skill)
if (skill) {
let translated = game.babele.translate("swade-core-rules.swade-skills", { name: skill.trim() }, true)
transl = translated.name || skill.trim()
}
return transl
},
"skill_swid": (swid) => {
if (swid == "fighting") return "combat";
if (swid == "shooting") return "tir";
return swid
},
"category_converter": (category) => {
return game.i18n.localize(category)
},
@ -183,14 +191,17 @@ Hooks.once('init', () => {
export class SwadeFRContentCommands {
static init() {
if (!game.swadeFRContent) {
const swadeFRCommands = new SwadeFRContentCommands()
swadeFRCommands.registerCommand({ path: ["/montremonsecret"], func: (content, msg, params) => SwadeFRContentCommands.enableSecret(), descr: "Affiche les compendiums secrets" });
swadeFRCommands.registerCommand({ path: ["/cachemonsecret"], func: (content, msg, params) => SwadeFRContentCommands.disableSecret(), descr: "Cache les compendiums secrets" });
swadeFRCommands.registerCommand({ path: ["/statparser"], func: (content, msg, params) => SwadeFRContentCommands.statParser(), descr: "Parse SW Delux stat block" });
game.swadeFRContent = { commands: swadeFRCommands }
}
Hooks.on("chatMessage", (html, content, msg) => {
console.log("CHAT PARSER!!!")
if (content[0] == '/') {
let regExp = /(\S+)/g;
let commands = content.match(regExp);
@ -268,13 +279,32 @@ export class SwadeFRContentCommands {
static disableSecret() {
game.settings.set("world", "swade-fr-content-hidden-compendiums", false)
}
/* -------------------------------------------- */
static statParser() {
let dialogue = new Dialog({
title: `Import`,
content: `<p>Stab block: <textarea id="swdelux-stat-parser" rows="20" cols="40"></textarea></p>`,
buttons: {
one: {
icon: '',
label: 'Parser !',
callback: (html) => {
let text = html.find('#swdelux-stat-parser').val();
let parser = new SWDELUXStatBlockParser(text);
parser.parse(text);
}
}
}
})
dialogue.render(true)
}
/* -------------------------------------------- */
_processCommand(commandsTable, name, params, content = '', msg = {}, path = "") {
console.log("===> Processing command")
let command = commandsTable[name];
path = path + name + " ";
if (command && command.subTable) {
if (command?.subTable) {
if (params[0]) {
return this._processCommand(command.subTable, params[0], params.slice(1), content, msg, path)
}
@ -283,7 +313,7 @@ export class SwadeFRContentCommands {
return true;
}
}
if (command && command.func) {
if (command?.func) {
const result = command.func(content, msg, params);
if (result == false) {
BoLCommands._chatAnswer(msg, command.descr);
@ -366,6 +396,7 @@ async function loadSecretCompendiums() {
/************************************************************************************/
Hooks.once('ready', () => {
console.log(">>>>>>>>>>")
// add hidden register
game.settings.register("world", "swade-fr-content-hidden-compendiums", {
@ -376,7 +407,7 @@ Hooks.once('ready', () => {
type: Boolean,
onChange: lang => window.location.reload()
})
SwadeFRContentCommands.init()
//FolderTranslate.translateFolders()
@ -386,5 +417,8 @@ Hooks.once('ready', () => {
/************************************************************************************/
Hooks.once('babele.ready', () => {
console.log(">>>>>>>>>> BABELE READY")
loadSecretCompendiums()
});
console.log(">>>>>>>>>>>> LOADED")