2021-03-25 00:14:56 +01:00
|
|
|
import { Grammar } from "./grammar.js";
|
2021-03-29 18:08:18 +02:00
|
|
|
import { Misc } from "./misc.js";
|
2021-03-25 00:14:56 +01:00
|
|
|
|
2021-01-08 22:23:50 +01:00
|
|
|
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"]];
|
|
|
|
|
2021-03-29 18:08:18 +02:00
|
|
|
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;
|
2021-03-17 01:21:37 +01:00
|
|
|
/* -------------------------------------------- */
|
|
|
|
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 }
|
|
|
|
];
|
2021-01-21 00:05:22 +01:00
|
|
|
|
2021-03-15 00:07:53 +01:00
|
|
|
/* -------------------------------------------- */
|
|
|
|
const categorieCompetences = {
|
2021-03-29 14:41:25 +02:00
|
|
|
"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" }
|
2021-03-15 00:07:53 +01:00
|
|
|
}
|
|
|
|
|
2021-03-19 22:20:01 +01:00
|
|
|
const compendiumCompetences = {
|
|
|
|
"personnage": "foundryvtt-reve-de-dragon.competences",
|
|
|
|
"creature": "foundryvtt-reve-de-dragon.competences-creatures",
|
|
|
|
"entite": "foundryvtt-reve-de-dragon.competences-entites"
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2021-01-21 00:05:22 +01:00
|
|
|
function _buildCumulXP() {
|
|
|
|
let cumulXP = { "-11": 0 };
|
|
|
|
let cumul = 0;
|
2021-03-29 18:08:18 +02:00
|
|
|
for (let i = 0; i <= xp_par_niveau.length; i++) {
|
2021-01-21 00:05:22 +01:00
|
|
|
let level = i - 10;
|
2021-03-29 18:08:18 +02:00
|
|
|
cumul += xp_par_niveau[i];
|
2021-01-21 00:05:22 +01:00
|
|
|
cumulXP[level] = cumul;
|
|
|
|
}
|
|
|
|
return cumulXP;
|
|
|
|
}
|
|
|
|
|
|
|
|
const competence_xp_cumul = _buildCumulXP();
|
2021-01-08 22:23:50 +01:00
|
|
|
|
2020-12-12 21:58:44 +01:00
|
|
|
export class RdDItemCompetence extends Item {
|
|
|
|
|
2021-03-25 17:51:03 +01:00
|
|
|
/* -------------------------------------------- */
|
2022-10-08 14:25:31 +02:00
|
|
|
static actorCompendium(actorType = undefined) {
|
|
|
|
return compendiumCompetences[actorType ?? 'personnage'];
|
2021-03-19 22:20:01 +01:00
|
|
|
}
|
|
|
|
|
2021-03-25 17:51:03 +01:00
|
|
|
/* -------------------------------------------- */
|
2021-03-15 00:07:53 +01:00
|
|
|
static getCategorieCompetences() {
|
|
|
|
return categorieCompetences;
|
|
|
|
}
|
2021-03-25 17:51:03 +01:00
|
|
|
/* -------------------------------------------- */
|
2021-03-17 01:21:37 +01:00
|
|
|
static getNiveauBase(category) {
|
2021-04-04 18:37:16 +02:00
|
|
|
return categorieCompetences[category].base;
|
2021-03-15 00:07:53 +01:00
|
|
|
}
|
2021-03-25 17:51:03 +01:00
|
|
|
/* -------------------------------------------- */
|
2021-03-17 01:21:37 +01:00
|
|
|
static getLabelCategorie(category) {
|
2021-03-15 00:07:53 +01:00
|
|
|
return categorieCompetences[category].label;
|
|
|
|
}
|
|
|
|
|
2021-03-29 18:08:18 +02:00
|
|
|
/* -------------------------------------------- */
|
|
|
|
static getCategorie(competence) {
|
2022-06-12 09:46:58 +02:00
|
|
|
return competence?.system.categorie;
|
2021-03-29 18:08:18 +02:00
|
|
|
}
|
|
|
|
static isDraconic(competence) {
|
2022-06-12 09:46:58 +02:00
|
|
|
return competence?.system.categorie == 'draconic';
|
2021-03-29 18:08:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
static getVoieDraconic(competences, voie) {
|
2021-11-23 02:11:24 +01:00
|
|
|
return RdDItemCompetence.findCompetence(competences.filter(it => RdDItemCompetence.isDraconic(it)), voie);
|
2021-03-18 23:55:26 +01:00
|
|
|
}
|
|
|
|
|
2020-12-12 21:58:44 +01:00
|
|
|
/* -------------------------------------------- */
|
2021-01-08 22:23:50 +01:00
|
|
|
static isCompetenceArme(competence) {
|
2022-10-08 14:25:31 +02:00
|
|
|
if (competence.isCompetence()) {
|
|
|
|
switch (competence.system.categorie) {
|
|
|
|
case 'melee':
|
|
|
|
return !Grammar.toLowerCaseNoAccent(competence.name).includes('esquive');
|
|
|
|
case 'tir':
|
|
|
|
case 'lancer':
|
|
|
|
return true;
|
|
|
|
}
|
2021-01-08 22:23:50 +01:00
|
|
|
}
|
|
|
|
return false;
|
2020-12-12 21:58:44 +01:00
|
|
|
}
|
2021-01-08 22:23:50 +01:00
|
|
|
|
|
|
|
/* -------------------------------------------- */
|
2020-12-12 21:58:44 +01:00
|
|
|
static isArmeUneMain(competence) {
|
2022-10-08 14:25:31 +02:00
|
|
|
return RdDItemCompetence.isCompetenceArme(competence) && competence.name.toLowerCase().includes("1 main");
|
2021-01-08 22:23:50 +01:00
|
|
|
}
|
|
|
|
static isArme2Main(competence) {
|
2022-10-08 14:25:31 +02:00
|
|
|
return RdDItemCompetence.isCompetenceArme(competence) && competence.name.toLowerCase().includes("2 main");
|
|
|
|
}
|
|
|
|
|
|
|
|
static isThanatos(competence) {
|
|
|
|
return competence.isCompetencePersonnage() && Grammar.toLowerCaseNoAccent(competence.name).includes('thanatos');
|
2020-12-12 21:58:44 +01:00
|
|
|
}
|
|
|
|
|
2021-01-08 22:23:50 +01:00
|
|
|
/* -------------------------------------------- */
|
2020-12-20 21:54:09 +01:00
|
|
|
static isMalusEncombrementTotal(competence) {
|
2022-06-12 12:14:55 +02:00
|
|
|
return competence?.name.toLowerCase().match(/(natation|acrobatie)/) || 0;
|
2020-12-20 21:54:09 +01:00
|
|
|
}
|
2021-01-01 22:25:32 +01:00
|
|
|
|
2021-01-08 22:23:50 +01:00
|
|
|
/* -------------------------------------------- */
|
2022-03-22 23:36:46 +01:00
|
|
|
static getListTronc(compName) {
|
2021-01-08 22:23:50 +01:00
|
|
|
for (let troncList of competenceTroncs) {
|
|
|
|
for (let troncName of troncList) {
|
|
|
|
if (troncName == compName)
|
|
|
|
return troncList;
|
|
|
|
}
|
|
|
|
}
|
2022-03-22 23:36:46 +01:00
|
|
|
return [];
|
2021-01-08 22:23:50 +01:00
|
|
|
}
|
2021-03-17 01:21:37 +01:00
|
|
|
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
static computeTotalXP(competences) {
|
|
|
|
const total = competences.map(c => RdDItemCompetence.computeXP(c))
|
2021-03-29 18:08:18 +02:00
|
|
|
.reduce(Misc.sum(), 0);
|
2021-03-17 01:21:37 +01:00
|
|
|
const economieTronc = RdDItemCompetence.computeEconomieXPTronc(competences);
|
|
|
|
return total - economieTronc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
static computeXP(competence) {
|
2022-10-08 14:25:31 +02:00
|
|
|
const factor = RdDItemCompetence.isThanatos(competence) ? 2 : 1; // Thanatos compte double !
|
2022-06-12 08:17:59 +02:00
|
|
|
const xpNiveau = RdDItemCompetence.computeDeltaXP(competence.system.base, competence.system.niveau ?? competence.system.base);
|
|
|
|
const xp = competence.system.xp ?? 0;
|
|
|
|
const xpSort = competence.system.xp_sort ?? 0;
|
|
|
|
return factor * (xpNiveau + xp) + xpSort;
|
2021-03-17 01:21:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
static computeEconomieXPTronc(competences) {
|
|
|
|
return competenceTroncs.map(
|
|
|
|
list => list.map(name => RdDItemCompetence.findCompetence(competences, name))
|
2021-11-23 02:11:24 +01:00
|
|
|
// calcul du coût xp jusqu'au niveau 0 maximum
|
2022-04-30 19:15:55 +02:00
|
|
|
.map(it => RdDItemCompetence.computeDeltaXP(it?.system.base ?? -11, Math.min(it?.system.niveau ?? -11, 0)))
|
2021-11-23 02:11:24 +01:00
|
|
|
.sort(Misc.ascending())
|
|
|
|
.splice(0, list.length - 1) // prendre toutes les valeurs sauf l'une des plus élevées
|
|
|
|
.reduce(Misc.sum(), 0)
|
2021-03-29 18:08:18 +02:00
|
|
|
).reduce(Misc.sum(), 0);
|
2021-03-17 01:21:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
static computeDeltaXP(from, to) {
|
|
|
|
RdDItemCompetence._valideNiveau(from);
|
|
|
|
RdDItemCompetence._valideNiveau(to);
|
|
|
|
return competence_xp_cumul[to] - competence_xp_cumul[from];
|
|
|
|
}
|
|
|
|
|
2021-01-08 22:23:50 +01:00
|
|
|
/* -------------------------------------------- */
|
|
|
|
static computeCompetenceXPCost(competence) {
|
2022-06-12 08:17:59 +02:00
|
|
|
let xp = RdDItemCompetence.getDeltaXp(competence.system.base, competence.system.niveau ?? competence.system.base);
|
|
|
|
xp += competence.system.xp ?? 0;
|
2021-03-29 18:08:18 +02:00
|
|
|
if (compData.name.includes('Thanatos')) xp *= 2; /// Thanatos compte double !
|
2022-06-12 08:17:59 +02:00
|
|
|
xp += competence.system.xp_sort ?? 0;
|
2021-01-08 22:23:50 +01:00
|
|
|
return xp;
|
|
|
|
}
|
|
|
|
|
2021-02-06 23:51:04 +01:00
|
|
|
/* -------------------------------------------- */
|
2021-01-21 00:05:22 +01:00
|
|
|
static computeEconomieCompetenceTroncXP(competences) {
|
|
|
|
let economie = 0;
|
2021-01-08 22:23:50 +01:00
|
|
|
for (let troncList of competenceTroncs) {
|
2021-01-21 00:05:22 +01:00
|
|
|
let list = troncList.map(name => RdDItemCompetence.findCompetence(competences, name))
|
2022-06-12 09:46:58 +02:00
|
|
|
.sort(Misc.descending(c => this.system.niveau)); // tri du plus haut au plus bas
|
2021-03-22 20:10:37 +01:00
|
|
|
list.splice(0, 1); // ignorer la plus élevée
|
2022-06-12 08:17:59 +02:00
|
|
|
list.map(c => c).forEach(c => {
|
|
|
|
economie += RdDItemCompetence.getDeltaXp(c.system.base, Math.min(c.system.niveau, 0))
|
2021-01-21 00:05:22 +01:00
|
|
|
});
|
2021-01-08 22:23:50 +01:00
|
|
|
}
|
2021-01-21 00:05:22 +01:00
|
|
|
return economie;
|
2021-01-08 22:23:50 +01:00
|
|
|
}
|
2021-01-21 00:05:22 +01:00
|
|
|
|
2021-03-25 17:51:03 +01:00
|
|
|
/* -------------------------------------------- */
|
2022-09-07 00:09:17 +02:00
|
|
|
static levelUp(item, stressTransforme) {
|
|
|
|
item.system.xpNext = RdDItemCompetence.getCompetenceNextXp(item.system.niveau);
|
|
|
|
const xpManquant = item.system.xpNext - item.system.xp;
|
|
|
|
item.system.isLevelUp = xpManquant <= 0;
|
|
|
|
item.system.isStressLevelUp = (xpManquant > 0 && stressTransforme >= xpManquant && item.system.niveau < item.system.niveau_archetype);
|
|
|
|
item.system.stressXpMax = 0;
|
|
|
|
if (xpManquant > 0 && stressTransforme > 0 && item.system.niveau < item.system.niveau_archetype) {
|
|
|
|
item.system.stressXpMax = Math.min(xpManquant , stressTransforme);
|
2021-11-23 02:11:24 +01:00
|
|
|
}
|
2021-03-17 01:21:37 +01:00
|
|
|
}
|
|
|
|
|
2021-03-25 17:51:03 +01:00
|
|
|
/* -------------------------------------------- */
|
2022-09-07 18:47:56 +02:00
|
|
|
static isVisible(item) {
|
|
|
|
return Number(item.system.niveau) != RdDItemCompetence.getNiveauBase(item.system.categorie);
|
2021-03-17 01:21:37 +01:00
|
|
|
}
|
2021-03-22 20:10:37 +01:00
|
|
|
|
2022-09-07 18:47:56 +02:00
|
|
|
static nomContientTexte(item, texte) {
|
|
|
|
return Grammar.toLowerCaseNoAccent(item.name).includes(Grammar.toLowerCaseNoAccent(texte))
|
2021-11-26 01:02:44 +01:00
|
|
|
}
|
|
|
|
|
2021-03-17 01:21:37 +01:00
|
|
|
/* -------------------------------------------- */
|
2022-09-07 18:47:56 +02:00
|
|
|
static isNiveauBase(item) {
|
|
|
|
return Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie);
|
2021-03-17 01:21:37 +01:00
|
|
|
}
|
|
|
|
|
2021-01-08 22:23:50 +01:00
|
|
|
/* -------------------------------------------- */
|
2021-11-20 01:04:22 +01:00
|
|
|
static findCompetence(list, idOrName, options = {}) {
|
2022-07-08 01:22:53 +02:00
|
|
|
if (idOrName == undefined) {
|
|
|
|
return undefined;
|
|
|
|
}
|
2022-10-08 14:25:31 +02:00
|
|
|
options = mergeObject(options, { preFilter: it => it.isCompetence(), description: 'compétence', });
|
|
|
|
return list.find(it => it.id == idOrName && it.isCompetence())
|
2021-11-20 01:04:22 +01:00
|
|
|
?? Misc.findFirstLike(idOrName, list, options);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
static findCompetences(list, name) {
|
2022-10-08 14:25:31 +02:00
|
|
|
return Misc.findAllLike(name, list, { filter: it => it.isCompetence(), description: 'compétence' });
|
2021-01-08 22:23:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
static getCompetenceNextXp(niveau) {
|
2021-01-21 00:05:22 +01:00
|
|
|
return RdDItemCompetence.getCompetenceXp(niveau + 1);
|
|
|
|
}
|
|
|
|
|
2021-02-06 23:51:04 +01:00
|
|
|
/* -------------------------------------------- */
|
2021-01-21 00:05:22 +01:00
|
|
|
static getCompetenceXp(niveau) {
|
|
|
|
RdDItemCompetence._valideNiveau(niveau);
|
2021-03-29 18:08:18 +02:00
|
|
|
return niveau < -10 ? 0 : xp_par_niveau[niveau + 10];
|
2021-01-21 00:05:22 +01:00
|
|
|
}
|
|
|
|
|
2021-02-06 23:51:04 +01:00
|
|
|
/* -------------------------------------------- */
|
2021-01-21 00:05:22 +01:00
|
|
|
static getDeltaXp(from, to) {
|
|
|
|
RdDItemCompetence._valideNiveau(from);
|
|
|
|
RdDItemCompetence._valideNiveau(to);
|
|
|
|
return competence_xp_cumul[to] - competence_xp_cumul[from];
|
|
|
|
}
|
|
|
|
|
2021-02-06 23:51:04 +01:00
|
|
|
/* -------------------------------------------- */
|
2021-03-22 20:10:37 +01:00
|
|
|
static _valideNiveau(niveau) {
|
2021-03-29 18:08:18 +02:00
|
|
|
if (niveau < -11 || niveau > niveau_max) {
|
|
|
|
console.warn(`Niveau ${niveau} en dehors des niveaux de compétences: [-11, ${niveau_max} ]`);
|
2021-01-21 00:05:22 +01:00
|
|
|
}
|
2021-01-08 22:23:50 +01:00
|
|
|
}
|
2021-03-22 20:10:37 +01:00
|
|
|
|
2021-03-17 01:21:37 +01:00
|
|
|
/* -------------------------------------------- */
|
|
|
|
static computeResumeArchetype(competences) {
|
|
|
|
const archetype = RdDItemCompetence.getLimitesArchetypes();
|
2022-06-12 08:17:59 +02:00
|
|
|
competences.map(it => Math.max(0, it.system.niveau_archetype))
|
2021-03-29 18:08:18 +02:00
|
|
|
.forEach(niveau => {
|
|
|
|
archetype[niveau] = archetype[niveau] ?? { "niveau": niveau, "nombreMax": 0, "nombre": 0 };
|
|
|
|
archetype[niveau].nombre = (archetype[niveau]?.nombre ?? 0) + 1;
|
|
|
|
});
|
2021-03-17 01:21:37 +01:00
|
|
|
return archetype;
|
|
|
|
}
|
|
|
|
|
2021-03-22 20:10:37 +01:00
|
|
|
/* -------------------------------------------- */
|
|
|
|
static getLimitesArchetypes() {
|
|
|
|
return duplicate(limitesArchetypes);
|
|
|
|
}
|
|
|
|
|
2020-12-12 21:58:44 +01:00
|
|
|
}
|