Files
foundryvtt-reve-de-dragon/module/rdd-carac.js

185 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
const TABLE_CARACTERISTIQUES_DERIVEES = {
// xp: coût pour passer du niveau inférieur à ce niveau
1: { xp: 3, niveau: -5, poids: "moins de 1kg", poidsMin: 0, poidsMax: 1, plusdom: -5, sconst: 0.5, sust: 0.1 },
2: { xp: 3, niveau: -4, poids: "1-5", poidsMin: 1, poidsMax: 5, plusdom: -4, sconst: 0.5, sust: 0.3 },
3: { xp: 4, niveau: -3, poids: "6-10", poidsMin: 6, poidsMax: 10, plusdom: -3, sconst: 1, sust: 0.5, beaute: 'hideux' },
4: { xp: 4, niveau: -2, poids: "11-20", poidsMin: 11, poidsMax: 20, plusdom: -3, sconst: 1, sust: 1, beaute: 'repoussant' },
5: { xp: 5, niveau: -1, poids: "21-30", poidsMin: 21, poidsMax: 30, plusdom: -2, sconst: 1, sust: 1, beaute: 'franchement très laid' },
6: { xp: 5, niveau: 0, poids: "31-40", poidsMin: 31, poidsMax: 40, plusdom: -1, sconst: 2, sust: 2, beaute: 'laid' },
7: { xp: 6, niveau: 0, poids: "41-50", poidsMin: 41, poidsMax: 50, plusdom: -1, sconst: 2, sust: 2, beaute: 'très désavantagé' },
8: { xp: 6, niveau: 0, poids: "51-60", poidsMin: 51, poidsMax: 60, plusdom: 0, sconst: 2, sust: 2, beaute: 'désavantagé' },
9: { xp: 7, niveau: 0, poids: "61-65", poidsMin: 61, poidsMax: 65, plusdom: 0, sconst: 3, sust: 2, beaute: 'pas terrible' },
10: { xp: 7, niveau: 0, poids: "66-70", poidsMin: 66, poidsMax: 70, plusdom: 0, sconst: 3, sust: 3, beaute: 'commun' },
11: { xp: 8, niveau: 1, poids: "71-75", poidsMin: 71, poidsMax: 75, plusdom: 0, sconst: 3, sust: 3, beaute: 'pas mal' },
12: { xp: 8, niveau: 1, poids: "76-80", poidsMin: 76, poidsMax: 80, plusdom: +1, sconst: 4, sust: 3, beaute: 'avantagé' },
13: { xp: 9, niveau: 2, poids: "81-90", poidsMin: 81, poidsMax: 90, plusdom: +1, sconst: 4, sust: 3, beaute: 'mignon' },
14: { xp: 9, niveau: 2, poids: "91-100", poidsMin: 91, poidsMax: 100, plusdom: +2, sconst: 4, sust: 4, beaute: 'beau' },
15: { xp: 10, niveau: 3, poids: "101-110", poidsMin: 101, poidsMax: 110, plusdom: +2, sconst: 5, sust: 4, beaute: 'très beau' },
16: { xp: 20, niveau: 3, poids: "111-120", poidsMin: 111, poidsMax: 120, plusdom: +3, sconst: 5, sust: 4, beaute: 'éblouissant' },
17: { xp: 30, niveau: 4, poids: "121-131", poidsMin: 121, poidsMax: 131, plusdom: +3, sconst: 5, sust: 5 },
18: { xp: 40, niveau: 4, poids: "131-141", poidsMin: 131, poidsMax: 141, plusdom: +4, sconst: 6, sust: 5 },
19: { xp: 50, niveau: 5, poids: "141-150", poidsMin: 141, poidsMax: 150, plusdom: +4, sconst: 6, sust: 5 },
20: { xp: 60, niveau: 5, poids: "151-160", poidsMin: 151, poidsMax: 160, plusdom: +4, sconst: 6, sust: 6 },
21: { xp: 70, niveau: 6, poids: "161-180", poidsMin: 161, poidsMax: 180, plusdom: +5, sconst: 7, sust: 6 },
22: { xp: 80, niveau: 6, poids: "181-200", poidsMin: 181, poidsMax: 200, plusdom: +5, sconst: 7, sust: 7 },
23: { xp: 90, niveau: 7, poids: "201-300", poidsMin: 201, poidsMax: 300, plusdom: +6, sconst: 7, sust: 8 },
24: { xp: 100, niveau: 7, poids: "301-400", poidsMin: 301, poidsMax: 400, plusdom: +6, sconst: 8, sust: 9 },
25: { xp: 110, niveau: 8, poids: "401-500", poidsMin: 401, poidsMax: 500, plusdom: +7, sconst: 8, sust: 10 },
26: { xp: 120, niveau: 8, poids: "501-600", poidsMin: 501, poidsMax: 600, plusdom: +7, sconst: 8, sust: 11 },
27: { xp: 130, niveau: 9, poids: "601-700", poidsMin: 601, poidsMax: 700, plusdom: +8, sconst: 9, sust: 12 },
28: { xp: 140, niveau: 9, poids: "701-800", poidsMin: 701, poidsMax: 800, plusdom: +8, sconst: 9, sust: 13 },
29: { xp: 150, niveau: 10, poids: "801-900", poidsMin: 801, poidsMax: 900, plusdom: +9, sconst: 9, sust: 14 },
30: { xp: 160, niveau: 10, poids: "901-1000", poidsMin: 901, poidsMax: 1000, plusdom: +9, sconst: 10, sust: 15 },
31: { xp: 170, niveau: 11, poids: "1001-1500", poidsMin: 1001, poidsMax: 1500, plusdom: +10, sconst: 10, sust: 16 },
32: { xp: 180, niveau: 11, poids: "1501-2000", poidsMin: 1501, poidsMax: 2000, plusdom: +11, sconst: 10, sust: 17 }
};
export const CARACS = {
TAILLE: 'taille',
APPARENCE: 'apparence',
CONSTITUTION: 'constitution',
FORCE: 'force',
AGILITE: 'agilite',
DEXTERITE: 'dexterite',
VUE: 'vue',
OUIE: 'ouie',
ODORATGOUT: 'odoratgout',
VOLONTE: 'volonte',
INTELLECT: 'intellect',
EMPATHIE: 'empathie',
REVE: 'reve',
CHANCE: 'chance',
}
export const LIST_CARAC_PERSONNAGE = {
[CARACS.TAILLE]: { code: CARACS.TAILLE, label: 'Taille', isCarac: true, path: 'system.carac.taille.value' },
[CARACS.APPARENCE]: { code: CARACS.APPARENCE, label: 'Apparence', isCarac: true, path: 'system.carac.apparence.value' },
[CARACS.CONSTITUTION]: { code: CARACS.CONSTITUTION, label: 'Constitution', isCarac: true, path: 'system.carac.constitution.value' },
[CARACS.FORCE]: { code: CARACS.FORCE, label: 'Force', isCarac: true, path: 'system.carac.force.value' },
[CARACS.AGILITE]: { code: CARACS.AGILITE, label: 'Agilité', isCarac: true, path: 'system.carac.agilite.value' },
[CARACS.DEXTERITE]: { code: CARACS.DEXTERITE, label: 'Dextérité', isCarac: true, path: 'system.carac.dexterite.value' },
[CARACS.VUE]: { code: CARACS.VUE, label: 'Vue', isCarac: true, path: 'system.carac.vue.value' },
[CARACS.OUIE]: { code: CARACS.OUIE, label: 'Ouïe', isCarac: true, path: 'system.carac.ouie.value' },
[CARACS.ODORATGOUT]: { code: CARACS.ODORATGOUT, label: 'Odorat-Goût', isCarac: true, path: 'system.carac.odoratgout.value' },
[CARACS.VOLONTE]: { code: CARACS.VOLONTE, label: 'Volonté', isCarac: true, path: 'system.carac.volonte.value' },
[CARACS.INTELLECT]: { code: CARACS.INTELLECT, label: 'Intellect', isCarac: true, path: 'system.carac.intellect.value' },
[CARACS.EMPATHIE]: { code: CARACS.EMPATHIE, label: 'Empathie', isCarac: true, path: 'system.carac.empathie.value' },
[CARACS.REVE]: { code: CARACS.REVE, label: 'Rêve', isCarac: true, path: 'system.carac.reve.value' },
[CARACS.CHANCE]: { code: CARACS.CHANCE, label: 'Chance', isCarac: true, path: 'system.carac.chance.value' },
'protection': { code: 'protection', label: 'Protection naturelle', isCarac: false, path: 'system.attributs.protection.value' },
'beaute': { code: 'beaute', label: 'Beauté', isCarac: false, path: 'system.background.beaute.value' }
}
export const LIST_CARAC_AUTRES = {
'perception': { code: 'perception', label: 'Perception', path: 'system.carac.perception.value' },
}
const LIST_CARAC_DERIVEE = {
'melee': { code: "melee", label: 'Mêlée', path: 'system.carac.melee.value' },
'tir': { code: "tir", label: 'Tir', path: 'system.carac.tir.value' },
'lancer': { code: "lancer", label: 'Lancer', path: 'system.carac.lancer.value' },
'derobee': { code: "derobee", label: 'Dérobée', path: 'system.carac.derobee.value' },
'chance-actuelle': { code: "chance-actuelle", label: 'Chance actuelle', path: 'system.carac.lancer.value' },
'reve-actuel': { code: "reve-actuel", label: 'Rêve actuel', path: 'system.reve.reve.value' },
}
export const LIST_CARAC_ROLL = Object.values(LIST_CARAC_PERSONNAGE).filter(it => it.isCarac && it.code != 'taille')
.concat(Object.values(LIST_CARAC_AUTRES))
.concat(Object.values(LIST_CARAC_DERIVEE))
export class RdDCarac {
static caracDetails(name, options = { onMessage: undefined }) {
let entry = Misc.findFirstLike(name, LIST_CARAC_ROLL, { mapper: it => it.code, description: 'caractéristique', onMessage: m => { } })
if (entry) {
return entry
}
return Misc.findFirstLike(name, LIST_CARAC_ROLL, { mapper: it => it.label, description: 'caractéristique', onMessage: options.onMessage })
}
static carac(code) {
return LIST_CARAC_PERSONNAGE[code]
}
static label(code) {
return RdDCarac.carac(code)?.label ?? '---'
}
static caracs(filter = it => it.isCarac) {
return Object.values(LIST_CARAC_PERSONNAGE).filter(filter)
}
static isAgiliteOuDerobee(caracLabel) {
return RdDCarac.isAgilite(caracLabel)
|| RdDCarac.isDerobee(caracLabel)
}
static isDerobee(caracLabel) {
return Grammar.equalsInsensitive(caracLabel, LIST_CARAC_PERSONNAGE.agilite.code);
}
static isAgilite(caracLabel) {
return Grammar.equalsInsensitive(caracLabel, LIST_CARAC_DERIVEE.derobee.code);
}
static isIntellect(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel) == 'intellect';
}
static isVolonte(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel) == 'volonte';
}
static isChance(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel)?.match(/chance(( |-)?actuelle)?/);
}
static isReve(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel)?.match(/reve(( |-)?actuel)?/);
}
/**
* Lappel à la chance nest possible que pour recommencer les jets dactions physiques :
* tous les jets de combat, de FORCE, dAGILITÉ, de DEXTÉRITÉ, de Dérobée, dAPPARENCE,
* ainsi que de Perception active et volontaire.
* Le moral ne s'utilise aussi que sur les actions physiques
*/
static isActionPhysique(caracLabel) {
return Grammar.toLowerCaseNoAccent(caracLabel)
?.match(/(apparence|force|agilite|dexterite|vue|ouie|gout|odorat|empathie|melee|tir|lancer|derobee)/) != null
}
static getCaracDerivee(value) {
return TABLE_CARACTERISTIQUES_DERIVEES[Math.min(Math.max(Math.floor(Number(value)), 1), 32)];
}
static computeTotal(carac, beaute = undefined) {
const total = Object.values(carac ?? {}).filter(c => !c.derivee)
.map(it => parseInt(it.value))
.reduce(Misc.sum(), 0);
const beauteSuperieur10 = Math.max((beaute ?? 10) - 10, 0);
return total + beauteSuperieur10;
}
static levelUp(it) {
it.xpNext = RdDCarac.getCaracNextXp(it.value);
it.isLevelUp = (it.xp >= it.xpNext);
}
/* -------------------------------------------- */
static calculSConst(constitution) {
return RdDCarac.getCaracDerivee(constitution).sconst;
}
/* -------------------------------------------- */
static getCaracNextXp(value) {
const nextValue = Number(value) + 1;
// xp est le coût pour atteindre cette valeur, on regarde donc le coût de la valeur+1
return RdDCarac.getCaracXp(nextValue);
}
static getCaracXp(targetValue) {
return RdDCarac.getCaracDerivee(targetValue)?.xp ?? 200;
}
}