f91dfd04a2
La recherche de compétence cherchait dans tous les items (y compris les armes), ce qui affichait des messages ui
264 lines
9.5 KiB
JavaScript
264 lines
9.5 KiB
JavaScript
import { Grammar } from "./grammar.js";
|
|
import { Misc } from "./misc.js";
|
|
|
|
const competenceTroncs = [["Esquive", "Dague", "Corps à corps"],
|
|
["Epée à 1 main", "Epée à 2 mains", "Hache à 1 main", "Hache à 2 mains", "Lance", "Masse à 1 main", "Masse à 2 mains"]];
|
|
|
|
const xp_par_niveau = [5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20, 30, 30, 40, 40, 60, 60, 100, 100, 100, 100, 100, 100, 100, 100, 100];
|
|
const niveau_max = xp_par_niveau.length - 10;
|
|
/* -------------------------------------------- */
|
|
const limitesArchetypes = [
|
|
{ "niveau": 0, "nombreMax": 100, "nombre": 0 },
|
|
{ "niveau": 1, "nombreMax": 10, "nombre": 0 },
|
|
{ "niveau": 2, "nombreMax": 9, "nombre": 0 },
|
|
{ "niveau": 3, "nombreMax": 8, "nombre": 0 },
|
|
{ "niveau": 4, "nombreMax": 7, "nombre": 0 },
|
|
{ "niveau": 5, "nombreMax": 6, "nombre": 0 },
|
|
{ "niveau": 6, "nombreMax": 5, "nombre": 0 },
|
|
{ "niveau": 7, "nombreMax": 4, "nombre": 0 },
|
|
{ "niveau": 8, "nombreMax": 3, "nombre": 0 },
|
|
{ "niveau": 9, "nombreMax": 2, "nombre": 0 },
|
|
{ "niveau": 10, "nombreMax": 1, "nombre": 0 },
|
|
{ "niveau": 11, "nombreMax": 1, "nombre": 0 }
|
|
];
|
|
|
|
/* -------------------------------------------- */
|
|
const categorieCompetences = {
|
|
"generale": { base: -4, label: "Générales" },
|
|
"particuliere": { base: -8, label: "Particulières" },
|
|
"specialisee": { base: -11, label: "Spécialisées" },
|
|
"connaissance": { base: -11, label: "Connaissances" },
|
|
"draconic": { base: -11, label: "Draconics" },
|
|
"melee": { base: -6, label: "Mêlée" },
|
|
"tir": { base: -8, label: "Tir" },
|
|
"lancer": { base: -8, label: "Lancer" }
|
|
}
|
|
|
|
const compendiumCompetences = {
|
|
"personnage": "foundryvtt-reve-de-dragon.competences",
|
|
"creature": "foundryvtt-reve-de-dragon.competences-creatures",
|
|
"entite": "foundryvtt-reve-de-dragon.competences-entites"
|
|
};
|
|
|
|
|
|
function _buildCumulXP() {
|
|
let cumulXP = { "-11": 0 };
|
|
let cumul = 0;
|
|
for (let i = 0; i <= xp_par_niveau.length; i++) {
|
|
let level = i - 10;
|
|
cumul += xp_par_niveau[i];
|
|
cumulXP[level] = cumul;
|
|
}
|
|
return cumulXP;
|
|
}
|
|
|
|
const competence_xp_cumul = _buildCumulXP();
|
|
|
|
export class RdDItemCompetence extends Item {
|
|
|
|
/* -------------------------------------------- */
|
|
static actorCompendium(actorType) {
|
|
return compendiumCompetences[actorType];
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static getCategorieCompetences() {
|
|
return categorieCompetences;
|
|
}
|
|
/* -------------------------------------------- */
|
|
static getNiveauBase(category) {
|
|
return categorieCompetences[category].base;
|
|
}
|
|
/* -------------------------------------------- */
|
|
static getLabelCategorie(category) {
|
|
return categorieCompetences[category].label;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static getCategorie(competence) {
|
|
return Misc.data(competence)?.data.categorie;
|
|
}
|
|
static isDraconic(competence) {
|
|
return Misc.data(competence)?.data.categorie == 'draconic';
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static getVoieDraconic(competences, voie) {
|
|
return RdDItemCompetence.findCompetence(competences.filter(it => RdDItemCompetence.isDraconic(it) ), voie);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static isCompetenceArme(competence) {
|
|
switch (Misc.templateData(competence).categorie) {
|
|
case 'melee':
|
|
return Misc.data(competence).name != 'Esquive';
|
|
case 'tir':
|
|
case 'lancer':
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static isArmeUneMain(competence) {
|
|
return Misc.data(competence)?.name.toLowerCase().includes("1 main");
|
|
}
|
|
static isArme2Main(competence) {
|
|
return Misc.data(competence)?.name.toLowerCase().includes("2 main");
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static isMalusEncombrementTotal(competence) {
|
|
return Misc.data(competence)?.name.toLowerCase().match(/(natation|acrobatie)/);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static isTronc(compName) {
|
|
for (let troncList of competenceTroncs) {
|
|
for (let troncName of troncList) {
|
|
if (troncName == compName)
|
|
return troncList;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static computeTotalXP(competences) {
|
|
const total = competences.map(c => RdDItemCompetence.computeXP(c))
|
|
.reduce(Misc.sum(), 0);
|
|
const economieTronc = RdDItemCompetence.computeEconomieXPTronc(competences);
|
|
return total - economieTronc;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static computeXP(competence) {
|
|
const itemData = Misc.data(competence);
|
|
const factor = itemData.name.includes('Thanatos') ? 2 : 1; // Thanatos compte double !
|
|
const xpNiveau = RdDItemCompetence.computeDeltaXP(itemData.data.base, itemData.data.niveau ?? itemData.data.base);
|
|
const xp = itemData.data.xp ?? 0;
|
|
const xpSort = itemData.data.xp_sort ?? 0;
|
|
return factor * (xpNiveau + xp) + xpSort;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static computeEconomieXPTronc(competences) {
|
|
return competenceTroncs.map(
|
|
list => list.map(name => RdDItemCompetence.findCompetence(competences, name))
|
|
// calcul du coût xp jusqu'au niveau 0 maximum
|
|
.map(it => RdDItemCompetence.computeDeltaXP(it?.data.base ?? -11, Math.min(it?.data.niveau ?? -11, 0)))
|
|
.sort(Misc.ascending())
|
|
.splice(0, list.length-1) // prendre toutes les valeurs sauf l'une des plus élevées
|
|
.reduce(Misc.sum(), 0)
|
|
).reduce(Misc.sum(), 0);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static computeDeltaXP(from, to) {
|
|
RdDItemCompetence._valideNiveau(from);
|
|
RdDItemCompetence._valideNiveau(to);
|
|
return competence_xp_cumul[to] - competence_xp_cumul[from];
|
|
}
|
|
|
|
|
|
/* -------------------------------------------- */
|
|
static computeCompetenceXPCost(competence) {
|
|
const compData = Misc.data(competence);
|
|
let xp = RdDItemCompetence.getDeltaXp(compData.data.base, compData.data.niveau ?? compData.data.base);
|
|
xp += compData.data.xp ?? 0;
|
|
if (compData.name.includes('Thanatos')) xp *= 2; /// Thanatos compte double !
|
|
xp += compData.data.xp_sort ?? 0;
|
|
return xp;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static computeEconomieCompetenceTroncXP(competences) {
|
|
let economie = 0;
|
|
for (let troncList of competenceTroncs) {
|
|
let list = troncList.map(name => RdDItemCompetence.findCompetence(competences, name))
|
|
.sort(Misc.descending(c => Misc.templateData(c).niveau)); // tri du plus haut au plus bas
|
|
list.splice(0, 1); // ignorer la plus élevée
|
|
list.map(c => Misc.templateData(c)).forEach(tplData => {
|
|
economie += RdDItemCompetence.getDeltaXp(tplData.base, Math.min(tplData.niveau, 0));
|
|
});
|
|
}
|
|
return economie;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static levelUp(itemData) {
|
|
itemData.data.xpNext = RdDItemCompetence.getCompetenceNextXp(itemData.data.niveau);
|
|
itemData.data.isLevelUp = itemData.data.xp >= itemData.data.xpNext;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static isVisible(itemData) {
|
|
return Number(itemData.data.niveau) != RdDItemCompetence.getNiveauBase(itemData.data.categorie);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static isNiveauBase(itemData) {
|
|
return Number(itemData.data.niveau) == RdDItemCompetence.getNiveauBase(itemData.data.categorie);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static findCompetence(list, idOrName, options = {}) {
|
|
options = mergeObject(options, {
|
|
filter: it => RdDItemCompetence.isCompetence(it),
|
|
description: 'compétence',
|
|
});
|
|
return list.find(it => it.id == idOrName && RdDItemCompetence.isCompetence(it))
|
|
?? Misc.findFirstLike(idOrName, list, options);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static findCompetences(list, name) {
|
|
return Misc.findAllLike(name, list, { filter: it => RdDItemCompetence.isCompetence(it), description: 'compétence' });
|
|
}
|
|
|
|
static isCompetence(item) {
|
|
return item.type == 'competence' || item.type == 'competencecreature';
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static getCompetenceNextXp(niveau) {
|
|
return RdDItemCompetence.getCompetenceXp(niveau + 1);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static getCompetenceXp(niveau) {
|
|
RdDItemCompetence._valideNiveau(niveau);
|
|
return niveau < -10 ? 0 : xp_par_niveau[niveau + 10];
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static getDeltaXp(from, to) {
|
|
RdDItemCompetence._valideNiveau(from);
|
|
RdDItemCompetence._valideNiveau(to);
|
|
return competence_xp_cumul[to] - competence_xp_cumul[from];
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static _valideNiveau(niveau) {
|
|
if (niveau < -11 || niveau > niveau_max) {
|
|
console.warn(`Niveau ${niveau} en dehors des niveaux de compétences: [-11, ${niveau_max} ]`);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static computeResumeArchetype(competences) {
|
|
const archetype = RdDItemCompetence.getLimitesArchetypes();
|
|
competences.map(it => Math.max(0, Misc.templateData(it).niveau_archetype))
|
|
.forEach(niveau => {
|
|
archetype[niveau] = archetype[niveau] ?? { "niveau": niveau, "nombreMax": 0, "nombre": 0 };
|
|
archetype[niveau].nombre = (archetype[niveau]?.nombre ?? 0) + 1;
|
|
});
|
|
return archetype;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static getLimitesArchetypes() {
|
|
return duplicate(limitesArchetypes);
|
|
}
|
|
|
|
} |