forked from public/swade-fr-content
Auto-patch skill and swid
This commit is contained in:
parent
2dab24eaa0
commit
b5ec752537
@ -3,7 +3,7 @@
|
||||
"mapping": {
|
||||
"description": "system.description",
|
||||
"skill": {
|
||||
"path": "system.actions.skill",
|
||||
"path": "system.actions.trait",
|
||||
"converter": "gear_skill"
|
||||
},
|
||||
"range": {
|
||||
|
@ -3,7 +3,7 @@
|
||||
"mapping": {
|
||||
"description": "system.description",
|
||||
"skill": {
|
||||
"path": "system.actions.skill",
|
||||
"path": "system.actions.trait",
|
||||
"converter": "gear_skill"
|
||||
},
|
||||
"range": {
|
||||
|
@ -3,7 +3,7 @@
|
||||
"mapping": {
|
||||
"description": "system.description",
|
||||
"skill": {
|
||||
"path": "system.actions.skill",
|
||||
"path": "system.actions.trait",
|
||||
"converter": "gear_skill"
|
||||
},
|
||||
"range": {
|
||||
|
@ -3,7 +3,7 @@
|
||||
"mapping": {
|
||||
"description": "system.description",
|
||||
"skill": {
|
||||
"path": "system.actions.skill",
|
||||
"path": "system.actions.trait",
|
||||
"converter": "gear_skill"
|
||||
},
|
||||
"range": {
|
||||
|
@ -3,7 +3,7 @@
|
||||
"mapping": {
|
||||
"description": "system.description",
|
||||
"skill": {
|
||||
"path": "system.actions.skill",
|
||||
"path": "system.actions.trait",
|
||||
"converter": "gear_skill"
|
||||
},
|
||||
"range": {
|
||||
|
@ -3,7 +3,7 @@
|
||||
"mapping": {
|
||||
"description": "system.description",
|
||||
"skill": {
|
||||
"path": "system.actions.skill",
|
||||
"path": "system.actions.trait",
|
||||
"converter": "gear_skill"
|
||||
},
|
||||
"range": {
|
||||
|
@ -3,7 +3,7 @@
|
||||
"mapping": {
|
||||
"description": "system.description",
|
||||
"skill": {
|
||||
"path": "system.actions.skill",
|
||||
"path": "system.actions.trait",
|
||||
"converter": "gear_skill"
|
||||
},
|
||||
"range": {
|
||||
|
@ -3,7 +3,7 @@
|
||||
"mapping": {
|
||||
"description": "system.description",
|
||||
"skill": {
|
||||
"path": "system.actions.skill",
|
||||
"path": "system.actions.trait",
|
||||
"converter": "gear_skill"
|
||||
},
|
||||
"range": {
|
||||
|
@ -3,7 +3,7 @@
|
||||
"mapping": {
|
||||
"description": "system.description",
|
||||
"skill": {
|
||||
"path": "system.actions.skill",
|
||||
"path": "system.actions.trait",
|
||||
"converter": "gear_skill"
|
||||
},
|
||||
"range": {
|
||||
|
@ -3,7 +3,7 @@
|
||||
"mapping": {
|
||||
"description": "system.description",
|
||||
"skill": {
|
||||
"path": "system.actions.skill",
|
||||
"path": "system.actions.trait",
|
||||
"converter": "gear_skill"
|
||||
},
|
||||
"range": {
|
||||
|
@ -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": [
|
||||
{
|
||||
|
@ -3,7 +3,7 @@
|
||||
"mapping": {
|
||||
"description": "system.description",
|
||||
"skill": {
|
||||
"path": "system.actions.skill",
|
||||
"path": "system.actions.trait",
|
||||
"converter": "gear_skill"
|
||||
},
|
||||
"range": {
|
||||
|
@ -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": {}
|
||||
}
|
||||
],
|
||||
|
116
modules/sw-statblock-parser.js
Normal file
116
modules/sw-statblock-parser.js
Normal 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 qu’ils ne le veuillent.Les caractéristiques disponibles ici s’appliquent aux oiseaux - tonnerre plus jeunes qui volent haut dans le ciel des Terres de chasse.Ces créatures ont l’apparence d’immenses et puissants oiseaux de proie, d’une majesté absolument terrifiante.Et pourtant, ces gardiens sont l’unique 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 d’un 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 d’Initiative. 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 qu’il 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 d’1 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é d’attaque 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);
|
||||
}
|
||||
}
|
||||
|
@ -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", {
|
||||
@ -386,5 +417,8 @@ Hooks.once('ready', () => {
|
||||
|
||||
/************************************************************************************/
|
||||
Hooks.once('babele.ready', () => {
|
||||
console.log(">>>>>>>>>> BABELE READY")
|
||||
loadSecretCompendiums()
|
||||
});
|
||||
|
||||
console.log(">>>>>>>>>>>> LOADED")
|
||||
|
Loading…
Reference in New Issue
Block a user