Compare commits

..

6 Commits

Author SHA1 Message Date
d7f2267d9c Version 12.0.26
Pour test de migration
2024-12-04 01:43:44 +01:00
57d35a0f9a Fix: sorts contenant des apostrophes
Le caractère utilisé dans le texte n'est pas l'apostrophe simple
informatique (utilisé dans les compendiums), et pas transformé
par toLowerCaseNoAccent...
2024-12-04 01:43:44 +01:00
417db33752 Parser: demi-rêve/valeurs actuelles/remise à neuf 2024-12-04 01:09:57 +01:00
bf0eea693a Migration draconic
Utilisation des noms de compétences draconiques standard
2024-12-04 01:09:22 +01:00
28ee8607bb Fix feuille simplifiée case TMR
Cases spéciales des TMRs mal gérée...
2024-12-04 01:09:22 +01:00
91717a3290 Bouton "don de haut-rêve"
Pour permettre au MJ de rendre un personnage haut rêvant
sans avoir à chercher dans les compendiums
2024-12-04 01:09:22 +01:00
8 changed files with 120 additions and 92 deletions

View File

@ -169,10 +169,10 @@ export class Mapping {
arme: arme arme: arme
} }
} }
static dommagesArme(actor, arme, maniement){ static dommagesArme(actor, arme, maniement) {
const dmgArme = RdDItemArme.dommagesReels(arme, maniement) const dmgArme = RdDItemArme.dommagesReels(arme, maniement)
const dommages = Misc.toSignedString(dmgArme + RdDBonus.bonusDmg(actor, maniement, dmgArme)) const dommages = Misc.toSignedString(dmgArme + RdDBonus.bonusDmg(actor, maniement, dmgArme))
switch(arme.system.mortalite) { switch (arme.system.mortalite) {
case 'non-mortel': return `(${dommages})` case 'non-mortel': return `(${dommages})`
case 'empoignade': return '-' case 'empoignade': return '-'
} }
@ -259,6 +259,9 @@ export class Mapping {
const diff = 'R' + RdDItemSort.addSpaceToNonNumeric(sort.system.difficulte) const diff = 'R' + RdDItemSort.addSpaceToNonNumeric(sort.system.difficulte)
return `${sort.name}${ptSeuil} (${caseTMR}) ${diff} ${coutReve}` return `${sort.name}${ptSeuil} (${caseTMR}) ${diff} ${coutReve}`
} }
static toVar(caseSpeciale) {
return Grammar.toLowerCaseNoAccent(caseSpeciale).startsWith('var') ? 'var' : caseSpeciale
}
static bonusCase(sort) { static bonusCase(sort) {
const list = RdDItemSort.stringToBonuscases(sort.system.bonuscase).sort(Misc.descending(it => it.bonus)) const list = RdDItemSort.stringToBonuscases(sort.system.bonuscase).sort(Misc.descending(it => it.bonus))

View File

@ -5,12 +5,12 @@ import { RdDBaseActorReve } from "../actor/base-actor-reve.js";
import { Grammar } from "../grammar.js"; import { Grammar } from "../grammar.js";
import { Misc } from "../misc.js"; import { Misc } from "../misc.js";
import { ENTITE_INCARNE, ENTITE_NONINCARNE } from "../constants.js"; import { ENTITE_INCARNE, ENTITE_NONINCARNE } from "../constants.js";
import { RdDItemTete } from "../item/tete.js";
const WHITESPACES = "\\s+" const WHITESPACES = "\\s+"
const NUMERIC = "[\\+\\-]?\\d+" const NUMERIC = "[\\+\\-]?\\d+"
const NUMERIC_VALUE = "(?<value>" + NUMERIC + ")" const NUMERIC_VALUE = "(?<value>" + NUMERIC + ")"
const XREGEXP_NAME = "(?<name>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+)"
const XREGEXP_COMP_CREATURE = WHITESPACES + "(?<carac>\\d+)" const XREGEXP_COMP_CREATURE = WHITESPACES + "(?<carac>\\d+)"
+ WHITESPACES + NUMERIC_VALUE + WHITESPACES + NUMERIC_VALUE
+ "(" + WHITESPACES + "(?<init>\\d+)?\\s+?(?<dommages>[\\+\\-]?\\d+)?" + ")?" + "(" + WHITESPACES + "(?<init>\\d+)?\\s+?(?<dommages>[\\+\\-]?\\d+)?" + ")?"
@ -22,11 +22,12 @@ const compParser = {
entite: XREGEXP_COMP_CREATURE entite: XREGEXP_COMP_CREATURE
} }
const XREGEXP_SORT_VOIE = "[OHNT\\/]+" const XREGEXP_SORT_VOIE = "(?<voies>[OHNT](\\/[OHNT])*)"
const XREGEXP_SORT_NAME = "(?<name>[^\\(]+)"
const XREGEXP_SORT_CASE = "\\((?<case>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+)\\)"; const XREGEXP_SORT_CASE = "\\((?<case>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+)\\)";
const XREGEXP_SORT = "(" + XREGEXP_SORT_VOIE const XREGEXP_SORT = "(" + XREGEXP_SORT_VOIE
+ WHITESPACES + XREGEXP_NAME + WHITESPACES + XREGEXP_SORT_NAME
+ WHITESPACES + XREGEXP_SORT_CASE + WHITESPACES + XREGEXP_SORT_CASE
+ WHITESPACES + "R(?<diff>([\\-\\d]+|(\\w|\\s)+))" + WHITESPACES + "R(?<diff>([\\-\\d]+|(\\w|\\s)+))"
+ WHITESPACES + "r(?<reve>(\\d+(\\+)?|\\s\\w+))" + WHITESPACES + "r(?<reve>(\\d+(\\+)?|\\s\\w+))"
@ -104,7 +105,7 @@ export class RdDStatBlockParser {
return "vaisseau"; return "vaisseau";
} }
static async parseStatBlock(statString, type = "npc") { static async parseStatBlock(statString) {
//statString = statBlock03; //statString = statBlock03;
if (!statString) { if (!statString) {
@ -122,10 +123,10 @@ export class RdDStatBlockParser {
statString = statString.trim(); statString = statString.trim();
// TODO: check for entite // TODO: check for entite
let actorType = RdDStatBlockParser.parseActorType(statString); let type = RdDStatBlockParser.parseActorType(statString);
// Now start carac // Now start carac
let actorData = foundry.utils.deepClone(game.model.Actor[actorType]); let actorData = foundry.utils.deepClone(game.model.Actor[type]);
for (let key in actorData.carac) { for (let key in actorData.carac) {
let caracDef = actorData.carac[key]; let caracDef = actorData.carac[key];
// Parse the stat string for each caracteristic // Parse the stat string for each caracteristic
@ -136,7 +137,7 @@ export class RdDStatBlockParser {
} }
// If creature we need to setup additionnal fields // If creature we need to setup additionnal fields
switch (actorType) { switch (type) {
case "creature": case "creature":
RdDStatBlockParser.parseCreature(statString, actorData) RdDStatBlockParser.parseCreature(statString, actorData)
break break
@ -147,14 +148,14 @@ export class RdDStatBlockParser {
let items = []; let items = [];
// Get skills from compendium // Get skills from compendium
const competences = await SystemCompendiums.getCompetences(actorType); const competences = await SystemCompendiums.getCompetences(type);
//console.log("Competences : ", competences); //console.log("Competences : ", competences);
for (let comp of competences) { for (let comp of competences) {
let compMatch = XRegExp.exec(statString, XRegExp(comp.name + compParser[actorType], 'giu')); let compMatch = XRegExp.exec(statString, XRegExp(comp.name + compParser[type], 'giu'));
if (compMatch) { if (compMatch) {
comp = comp.toObject() comp = comp.toObject()
comp.system.niveau = Number(compMatch.value); comp.system.niveau = Number(compMatch.value);
if (actorType == "creature" || actorType == "entite") { if (type == "creature" || type == "entite") {
comp.system.carac_value = Number(compMatch.carac); comp.system.carac_value = Number(compMatch.carac);
if (compMatch.dommages != undefined) { if (compMatch.dommages != undefined) {
comp.system.dommages = Number(compMatch.dommages); comp.system.dommages = Number(compMatch.dommages);
@ -163,7 +164,7 @@ export class RdDStatBlockParser {
} }
items.push(comp) items.push(comp)
} }
else if (actorType == "personnage") { else if (type == "personnage") {
comp = comp.toObject() comp = comp.toObject()
items.push(comp) items.push(comp)
} }
@ -213,81 +214,101 @@ export class RdDStatBlockParser {
} }
} }
// Attemp to detect spell
let hautRevant = false
let sorts = await SystemCompendiums.getWorldOrCompendiumItems("sort", "sorts-oniros")
sorts = sorts.concat(await SystemCompendiums.getWorldOrCompendiumItems("sort", "sorts-hypnos"))
sorts = sorts.concat(await SystemCompendiums.getWorldOrCompendiumItems("sort", "sorts-narcos"))
sorts = sorts.concat(await SystemCompendiums.getWorldOrCompendiumItems("sort", "sorts-thanatos"))
XRegExp.forEach(statString, XRegExp(XREGEXP_SORT, 'giu'), if (type == "personnage") {
await RdDStatBlockParser.parseHautReve(statString, actorData, items);
RdDStatBlockParser.parsePersonnage(statString, actorData);
}
let name = RdDStatBlockParser.extractName(type, statString);
let newActor = await RdDBaseActorReve.create({ name, type: type, system: actorData, items });
await newActor.remiseANeuf()
// DUmp....
console.log(actorData);
}
static async parseHautReve(statString, actorData, items) {
let hautRevant = false;
// Attemp to detect spell
let sorts = await SystemCompendiums.getWorldOrCompendiumItems("sort", "sorts-oniros");
sorts = sorts.concat(await SystemCompendiums.getWorldOrCompendiumItems("sort", "sorts-hypnos"));
sorts = sorts.concat(await SystemCompendiums.getWorldOrCompendiumItems("sort", "sorts-narcos"));
sorts = sorts.concat(await SystemCompendiums.getWorldOrCompendiumItems("sort", "sorts-thanatos"));
XRegExp.forEach(statString, XRegExp(XREGEXP_SORT, 'gu' /* keep case sensitive to match the spell draconic skill */),
function (matchSort, i) { function (matchSort, i) {
let sort = sorts.find(s => Grammar.equalsInsensitive(s.name, matchSort.name)) const sortName = Grammar.toLowerCaseNoAccent(matchSort.name).trim().replace("", "'");
let sort = sorts.find(s => Grammar.toLowerCaseNoAccent(s.name) == sortName)
if (sort) { if (sort) {
hautRevant = true hautRevant = true;
sort = sort.toObject(); sort = sort.toObject();
if (matchSort.bonus && matchSort.bonuscase) { if (matchSort.bonus && matchSort.bonuscase) {
sort.system.bonuscase = `${matchSort.bonuscase}:${matchSort.bonus}` sort.system.bonuscase = `${matchSort.bonuscase}:${matchSort.bonus}`;
} }
items.push(sort); items.push(sort);
} }
else{
ui.notifications.warn(`Impossible de trouver le sort ${matchSort.name} / ${sortName}`)
console.warn(`Impossible de trouver le sort ${matchSort.name} / ${sortName}`)
}
}); });
if (hautRevant) { if (hautRevant) {
const donHR = await RdDItemTete.teteDonDeHautReve() const donHR = await RdDItemTete.teteDonDeHautReve();
if (donHR) { if (donHR) {
items.push(donHR.toObject()); items.push(donHR.toObject());
} }
const demiReve = XRegExp.exec(statString, XRegExp("Demi-rêve\\s+(?<value>[A-M]\\d{1,2})", 'giu'))
actorData.reve.tmrpos.coord = demiReve?.value ?? 'A1'
} }
if (actorType == "personnage") { }
static parsePersonnage(statString, actorData) {
actorData.reve.seuil.value = actorData.carac.reve.value
let feminin = XRegExp.exec(statString, XRegExp("né(?<value>e?) à", 'giu')); const reveActuel = XRegExp.exec(statString, XRegExp("Rêve actuel\\s+(?<value>\\d+)", 'giu'))
actorData.sexe = (feminin?.value == 'e') ? 'féminin' : 'masculin' actorData.reve.reve.value = reveActuel?.value ? Number(reveActuel.value) : actorData.reve.seuil.value
// Get hour name : heure du XXXXX const feminin = XRegExp.exec(statString, XRegExp("né(?<value>e?) à", 'giu'));
let heure = XRegExp.exec(statString, XRegExp("heure (du|de la|des|de l\')\\s*(?<value>[A-Za-zÀ-ÖØ-öø-ÿ\\s]+),", 'giu')); actorData.sexe = (feminin?.value == 'e') ? 'féminin' : 'masculin';
actorData.heure = this.getHeureKey(heure?.value || "Vaisseau");
// Get age // Get hour name : heure du XXXXX
let age = XRegExp.exec(statString, XRegExp("(?<value>\\d+) ans", 'giu')); const heure = XRegExp.exec(statString, XRegExp("heure (du|de la|des|de l\')\\s*(?<value>[A-Za-zÀ-ÖØ-öø-ÿ\\s]+),", 'giu'));
if (age?.value) { actorData.heure = this.getHeureKey(heure?.value || "Vaisseau");
actorData.age = Number(age.value);
}
// Get height
let taille = XRegExp.exec(statString, XRegExp("(?<value>\\d+m\\d+)", 'giu'));
if (taille?.value) {
actorData.taille = taille.value;
}
// Get weight
let poids = XRegExp.exec(statString, XRegExp("(?<value>\\d+) kg", 'giu'));
if (poids?.value) {
actorData.poids = poids.value;
}
// Get cheveux
let cheveux = XRegExp.exec(statString, XRegExp("kg,\\s+(?<value>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+),\\s+yeux", 'giu'));
if (cheveux?.value) {
actorData.cheveux = cheveux.value;
}
// Get yeux
let yeux = XRegExp.exec(statString, XRegExp("yeux\\s+(?<value>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+), Beau", 'giu'));
if (yeux?.value) {
actorData.yeux = yeux.value;
}
// Get beauty // Get age
let beaute = XRegExp.exec(statString, XRegExp("beauté\\s+(?<value>\\d+)", 'giu')); const age = XRegExp.exec(statString, XRegExp("(?<value>\\d+) ans", 'giu'));
if (beaute?.value) { if (age?.value) {
actorData.beaute = Number(beaute.value); actorData.age = Number(age.value);
} }
// Get height
const taille = XRegExp.exec(statString, XRegExp("(?<value>\\d+m\\d+)", 'giu'));
if (taille?.value) {
actorData.taille = taille.value;
}
// Get weight
const poids = XRegExp.exec(statString, XRegExp("(?<value>\\d+) kg", 'giu'));
if (poids?.value) {
actorData.poids = poids.value;
}
// Get cheveux
const cheveux = XRegExp.exec(statString, XRegExp("kg,\\s+(?<value>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+),\\s+yeux", 'giu'));
if (cheveux?.value) {
actorData.cheveux = cheveux.value;
}
// Get yeux
const yeux = XRegExp.exec(statString, XRegExp("yeux\\s+(?<value>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+), Beau", 'giu'));
if (yeux?.value) {
actorData.yeux = yeux.value;
} }
// Name is all string before ', né' // Get beauty
let name = RdDStatBlockParser.extractName(actorType, statString); const beaute = XRegExp.exec(statString, XRegExp("beauté\\s+(?<value>\\d+)", 'giu'));
if (beaute?.value) {
let newActor = RdDBaseActorReve.create({ name: name || "Importé", type: actorType, system: actorData, items: items }); actorData.beaute = Number(beaute.value);
}
// DUmp....
console.log(actorData);
} }
static parseCreature(statString, actorData) { static parseCreature(statString, actorData) {
@ -349,24 +370,17 @@ export class RdDStatBlockParser {
static extractName(actorType, statString) { static extractName(actorType, statString) {
switch (actorType) { switch (actorType) {
case "personnage": return RdDStatBlockParser.extractNamePersonnage(statString); case "personnage":
case "creature": return RdDStatBlockParser.extractNameCreature(statString); // Name is all string before first comma ','
const namePersonnage = XRegExp.exec(statString, XRegExp("(?<value>[\\p{Letter}\\s\\d]+),", 'giu'));
if (namePersonnage?.value) {
return Misc.upperFirst(namePersonnage?.value);
}
} }
return RdDStatBlockParser.extractNameCreature(statString);
}
static extractNamePersonnage(statString) {
let name = XRegExp.exec(statString, XRegExp("(?<value>[\\p{Letter}\\s\\d]+),", 'giu'));
if (!name?.value) {
name = XRegExp.exec(statString, XRegExp("(?<value>.+)\\s+taille", 'giu'));
}
return Misc.upperFirst(name?.value || "Importé");
}
static extractNameCreature(statString) {
const name = XRegExp.exec(statString, XRegExp("(?<value>.+)\\s+taille", 'giu')); const name = XRegExp.exec(statString, XRegExp("(?<value>.+)\\s+taille", 'giu'));
return Misc.upperFirst(name?.value || "Importé"); return Misc.upperFirst(name?.value || "Importé");
} }
} }
/************************************************************************************/ /************************************************************************************/

View File

@ -137,7 +137,7 @@ class _10_0_21_VehiculeStructureResistanceMax extends Migration {
} }
class _10_0_33_MigrationNomsDraconic extends Migration { class _10_0_33_MigrationNomsDraconic extends Migration {
get code() { return "competences-creature-parade"; } get code() { return "competences-nom-draconic"; }
get version() { return "10.0.33"; } get version() { return "10.0.33"; }
migrationNomDraconic(ancien) { migrationNomDraconic(ancien) {
@ -530,15 +530,25 @@ class _11_2_20_MigrationAstrologie extends Migration {
} }
} }
class _12_0_24_MigrationVoieSorts extends Migration { class _12_0_26_MigrationVoieSorts extends Migration {
get code() { return "migration-voies-sorts" } get code() { return "migration-voies-sorts" }
get version() { return "12.0.24" } get version() { return "12.0.26" }
async migrate() { async migrate() {
await this.applyItemsUpdates(items => items await this.applyItemsUpdates(items => items
.filter(it => ITEM_TYPES.sort == it.type) .filter(it => [ITEM_TYPES.sort, ITEM_TYPES.sortreserve].includes(it.type))
.map(it => this.migrateSort(it)) .map(it => this.migrateSort(it))
) )
await this.applyItemsUpdates(items => items
.filter(it => ITEM_TYPES.competence == it.type && it.system.categorie == 'draconic')
.map(it => this.migrateDraconic(it))
)
}
migrateDraconic(it) {
return {
_id: it.id,
name: this.convertDraconic(it.name),
}
} }
migrateSort(it) { migrateSort(it) {
return { return {
@ -575,6 +585,7 @@ export class Migrations {
new _10_7_19_CategorieCompetenceCreature(), new _10_7_19_CategorieCompetenceCreature(),
new _10_7_19_PossessionsEntiteVictime(), new _10_7_19_PossessionsEntiteVictime(),
new _11_2_20_MigrationAstrologie(), new _11_2_20_MigrationAstrologie(),
new _12_0_26_MigrationVoieSorts()
]; ];
} }

View File

@ -1,4 +1,4 @@
name: Voie d'Hypnos name: Hypnos
type: competence type: competence
img: systems/foundryvtt-reve-de-dragon/icons/competence_hypnos.webp img: systems/foundryvtt-reve-de-dragon/icons/competence_hypnos.webp
_id: bt2cR4aE6lIOeg4F _id: bt2cR4aE6lIOeg4F

View File

@ -1,4 +1,4 @@
name: Voie de Narcos name: Narcos
type: competence type: competence
img: systems/foundryvtt-reve-de-dragon/icons/competence_narcos.webp img: systems/foundryvtt-reve-de-dragon/icons/competence_narcos.webp
_id: u1Peok1EYkBcVsmN _id: u1Peok1EYkBcVsmN

View File

@ -1,4 +1,4 @@
name: Voie d'Oniros name: Oniros
type: competence type: competence
img: systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp img: systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp
_id: nnR2UHelUaF8dxYn _id: nnR2UHelUaF8dxYn

View File

@ -1,4 +1,4 @@
name: Voie de Thanatos name: Thanatos
type: competence type: competence
img: systems/foundryvtt-reve-de-dragon/icons/competence_thanatos.webp img: systems/foundryvtt-reve-de-dragon/icons/competence_thanatos.webp
_id: dPlTQzvU3CEg5qKc _id: dPlTQzvU3CEg5qKc

View File

@ -1,9 +1,9 @@
{ {
"id": "foundryvtt-reve-de-dragon", "id": "foundryvtt-reve-de-dragon",
"title": "Rêve de Dragon", "title": "Rêve de Dragon",
"version": "12.0.24", "version": "12.0.26",
"download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/releases/download/12.0.24/rddsystem.zip", "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/releases/download/12.0.26/rddsystem.zip",
"manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/releases/download//12.0.24/system.json", "manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/releases/download/12.0.26/system.json",
"changelog": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md", "changelog": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md",
"compatibility": { "compatibility": {
"minimum": "11", "minimum": "11",