Vincent Vandemeulebrouck
9b1a179a71
- Utilisation du nom de voie (Oniros au lieu de Voie d'Oniros) - compatible anciens sorts - migration des objets existants - amélioration de l'affichage de la liste des sorts
378 lines
15 KiB
JavaScript
378 lines
15 KiB
JavaScript
import { Grammar } from "../../grammar.js"
|
|
import { RdDItemArme } from "../../item-arme.js"
|
|
import { RdDItemCompetence } from "../../item-competence.js"
|
|
import { RdDItemSort } from "../../item-sort.js"
|
|
import { ITEM_TYPES } from "../../item.js"
|
|
import { Misc } from "../../misc.js"
|
|
import { RdDTimestamp } from "../../time/rdd-timestamp.js"
|
|
import { RdDBonus } from "../../rdd-bonus.js"
|
|
import { TMRType } from "../../tmr-utility.js"
|
|
|
|
|
|
export const CATEGORIES_COMPETENCES = [
|
|
"generale",
|
|
"particuliere",
|
|
"specialisee",
|
|
"connaissance",
|
|
]
|
|
export const CATEGORIES_DRACONIC = [
|
|
"draconic",
|
|
]
|
|
|
|
const CATEGORIES_COMBAT = [
|
|
"melee",
|
|
"tir",
|
|
"lancer"
|
|
]
|
|
|
|
const NIVEAU_BASE = {
|
|
"generale": -4,
|
|
"particuliere": -8,
|
|
"specialisee": -11,
|
|
"connaissance": -11,
|
|
"draconic": -11,
|
|
"melee": -6,
|
|
"tir": -8,
|
|
"lancer": -8,
|
|
}
|
|
|
|
class ColumnMappingFactory {
|
|
static createMappingArme(part, i) {
|
|
return { column: `arme_${part}_${i}`, getter: (actor, context) => Mapping.getArme(actor, context, part, i) }
|
|
}
|
|
|
|
static createMappingSort(part, i) {
|
|
return { column: `sort_${part}_${i}`, getter: (actor, context) => Mapping.getSort(actor, context, part, i) }
|
|
}
|
|
}
|
|
|
|
const NB_ARMES = 10
|
|
const NB_SORTS = 20
|
|
const TABLEAU_ARMES = [...Array(NB_ARMES).keys()]
|
|
const TABLEAU_SORTS = [...Array(NB_SORTS).keys()]
|
|
|
|
const MAPPING_BASE = [
|
|
{ column: "ID", colName: 'ID', getter: (actor, context) => actor.id },
|
|
{ column: "name", getter: (actor, context) => actor.name },
|
|
{ column: "metier", colName: 'Métier', getter: (actor, context) => actor.system.metier },
|
|
{ column: "biographie", colName: 'Biographie', getter: (actor, context) => actor.system.biographie },
|
|
{ column: "taille", getter: (actor, context) => actor.system.carac.taille.value },
|
|
{ column: "apparence", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.apparence.value },
|
|
{ column: "constitution", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.constitution.value },
|
|
{ column: "force", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.force.value },
|
|
{ column: "agilite", rollClass: 'roll-carac', colName: 'Agilité', getter: (actor, context) => actor.system.carac.agilite.value },
|
|
{ column: "dexterite", rollClass: 'roll-carac', colName: 'Dextérité', getter: (actor, context) => actor.system.carac.dexterite.value },
|
|
{ column: "vue", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.vue.value },
|
|
{ column: "ouie", rollClass: 'roll-carac', colName: 'Ouïe', getter: (actor, context) => actor.system.carac.ouie.value },
|
|
{ column: "odoratgout", rollClass: 'roll-carac', colName: 'Odo-goût', getter: (actor, context) => actor.system.carac.odoratgout.value },
|
|
{ column: "volonte", rollClass: 'roll-carac', colName: 'Volonté', getter: (actor, context) => actor.system.carac.volonte.value },
|
|
{ column: "intellect", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.intellect.value },
|
|
{ column: "empathie", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.empathie.value },
|
|
{ column: "reve", rollClass: 'roll-carac', colName: 'Rêve', getter: (actor, context) => actor.system.carac.reve.value },
|
|
{ column: "chance", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.chance.value },
|
|
{ column: "melee", rollClass: 'roll-carac', colName: 'Mêlée', getter: (actor, context) => actor.system.carac.melee.value },
|
|
{ column: "tir", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.tir.value },
|
|
{ column: "lancer", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.lancer.value },
|
|
{ column: "derobee", rollClass: 'roll-carac', colName: 'Dérobée', getter: (actor, context) => actor.system.carac.derobee.value },
|
|
{ column: "vie", getter: (actor, context) => actor.system.sante.vie.max },
|
|
{ column: "endurance", getter: (actor, context) => actor.system.sante.endurance.max },
|
|
{ column: "plusdom", colName: '+dom', getter: (actor, context) => actor.system.attributs.plusdom.value },
|
|
{ column: "protectionnaturelle", colName: 'Protection naturelle', getter: (actor, context) => actor.system.attributs.protection.value > 0 ? actor.system.attributs.protection.value : '' },
|
|
{ column: "description", getter: (actor, context) => Mapping.getDescription(actor) },
|
|
{ column: "armure", getter: (actor, context) => Mapping.getArmure(actor, context) },
|
|
{ column: "protectionarmure", colName: 'Protection', getter: (actor, context) => Mapping.getProtectionArmure(actor, context) },
|
|
{ column: "malus_armure", getter: (actor, context) => Mapping.getMalusArmure(actor, context) },
|
|
{ column: "reve_actuel", rollClass: 'roll-reve-actuel', colName: 'Rêve actuel', getter: (actor, context) => actor.system.reve.reve.value },
|
|
{ column: "vie_actuel", rollClass: 'jet-vie', getter: (actor, context) => actor.system.sante.vie.value },
|
|
{ column: "endurance_actuel", rollClass: 'jet-endurance', getter: (actor, context) => actor.system.sante.endurance.value },
|
|
{ column: "esquive", getter: (actor, context) => Mapping.getEsquive(context) },
|
|
{ column: "esquive_armure", getter: (actor, context) => Mapping.getEsquiveArmure(context) },
|
|
{ column: "competences", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_COMPETENCES) },
|
|
{ column: "draconic", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_DRACONIC) },
|
|
]
|
|
|
|
const MAPPING_ARMES = TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('name', i))
|
|
.concat(TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('niveau', i)))
|
|
.concat(TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('init', i)))
|
|
.concat(TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('dommages', i)))
|
|
const MAPPING_SORTS = TABLEAU_SORTS.map(i => ColumnMappingFactory.createMappingSort('voie', i))
|
|
.concat(TABLEAU_SORTS.map(i => ColumnMappingFactory.createMappingSort('description', i)))
|
|
.concat(TABLEAU_SORTS.map(i => ColumnMappingFactory.createMappingSort('bonus', i)))
|
|
const MAPPING = MAPPING_BASE
|
|
.concat(MAPPING_ARMES)
|
|
.concat(MAPPING_SORTS)
|
|
|
|
export class Mapping {
|
|
|
|
static getMapping() {
|
|
return MAPPING
|
|
}
|
|
|
|
static getColumns() {
|
|
return MAPPING.map(it => it.column)
|
|
}
|
|
|
|
static getValues(actor) {
|
|
const context = Mapping.prepareContext(actor)
|
|
return MAPPING.map(it => it.getter(actor, context))
|
|
}
|
|
static getAsObject(actor) {
|
|
const context = Mapping.prepareContext(actor)
|
|
return Object.fromEntries(MAPPING.map(it => [it.column, {
|
|
colName: it.colName ?? it.column,
|
|
value: it.getter(actor, context)
|
|
}]))
|
|
}
|
|
|
|
static getValues(actor) {
|
|
const context = Mapping.prepareContext(actor)
|
|
return MAPPING.map(it => it.getter(actor, context))
|
|
}
|
|
|
|
static prepareContext(actor) {
|
|
return {
|
|
armes: Mapping.prepareArmes(actor),
|
|
armure: Mapping.prepareArmure(actor),
|
|
esquive: Mapping.prepareEsquive(actor),
|
|
sorts: Mapping.prepareSorts(actor)
|
|
}
|
|
}
|
|
|
|
static prepareArmes(actor) {
|
|
const armes = actor.items.filter(it => it.type == ITEM_TYPES.arme)
|
|
armes.push(RdDItemArme.corpsACorps(actor));
|
|
armes.push(RdDItemArme.empoignade(actor));
|
|
return armes.map(arme => [
|
|
arme.system.unemain ? Mapping.prepareArme(actor, arme, 'unemain') : undefined,
|
|
arme.system.deuxmains ? Mapping.prepareArme(actor, arme, 'deuxmains') : undefined,
|
|
!(arme.system.unemain || arme.system.deuxmains) ? Mapping.prepareArme(actor, arme, 'competence') : undefined,
|
|
arme.system.lancer != "" ? Mapping.prepareArme(actor, arme, 'lancer') : undefined,
|
|
arme.system.tir != "" ? Mapping.prepareArme(actor, arme, 'tir') : undefined]
|
|
.filter(it => it != undefined))
|
|
.reduce((a, b) => a.concat(b), [])
|
|
}
|
|
|
|
static prepareArme(actor, arme, maniement) {
|
|
const nameCompetenceArme = RdDItemArme.getCompetenceArme(arme, maniement)
|
|
const competence = actor.getCompetence(nameCompetenceArme)
|
|
if (RdDItemCompetence.isNiveauBase(competence)) {
|
|
return undefined
|
|
}
|
|
const categorie = Mapping.complementCategorie(arme, maniement)
|
|
const dommages = Mapping.dommagesArme(actor, arme, maniement)
|
|
return {
|
|
name: arme.name + categorie,
|
|
niveau: Misc.toSignedString(competence.system.niveau),
|
|
init: Mapping.calculBaseInit(actor, competence.system.categorie) + competence.system.niveau,
|
|
dommages: dommages,
|
|
competence: competence,
|
|
arme: arme
|
|
}
|
|
}
|
|
static dommagesArme(actor, arme, maniement){
|
|
const dmgArme = RdDItemArme.dommagesReels(arme, maniement)
|
|
const dommages = Misc.toSignedString(dmgArme + RdDBonus.bonusDmg(actor, maniement, dmgArme))
|
|
switch(arme.system.mortalite) {
|
|
case 'non-mortel': return `(${dommages})`
|
|
case 'empoignade': return '-'
|
|
}
|
|
return dommages
|
|
}
|
|
|
|
static complementCategorie(arme, maniement) {
|
|
switch (maniement) {
|
|
case 'unemain': return (arme.system.deuxmains) ? ' 1 main' : (arme.system.lancer || arme.system.tir) ? ' mêlée' : ''
|
|
case 'deuxmains': return (arme.system.unemain) ? ' 2 mains' : (arme.system.lancer || arme.system.tir) ? ' mêlée' : ''
|
|
case 'lancer': return (arme.system.unemain || arme.system.deuxmains || arme.system.tir) ? ' jet' : ''
|
|
case 'tir': return (arme.system.unemain || arme.system.deuxmains || arme.system.lancer) ? ' tir' : ''
|
|
}
|
|
return ''
|
|
}
|
|
|
|
static calculBaseInit(actor, categorie) {
|
|
const mapping = MAPPING_BASE.find(it => it.column == categorie)
|
|
if (mapping) {
|
|
switch (categorie) {
|
|
case 'melee':
|
|
case 'tir':
|
|
case 'lancer':
|
|
const caracteristique = Number(actor.system.carac[categorie].value)
|
|
return Math.floor(caracteristique / 2)
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
static prepareArmure(actor) {
|
|
const armures = actor.itemTypes[ITEM_TYPES.armure].filter(it => it.system.equipe)
|
|
if (armures.length > 1) {
|
|
console.warn(`${actor.name} a équipé ${armures.length} armures, seule la première sera considérée`)
|
|
}
|
|
if (armures.length > 0) {
|
|
const armure = armures[0]
|
|
return {
|
|
name: armure.name,
|
|
protection: armure.system.protection,
|
|
malus: armure.system.malus ?? 0
|
|
}
|
|
}
|
|
return {
|
|
name: '',
|
|
protection: actor.system.attributs.protection.value,
|
|
malus: 0
|
|
}
|
|
}
|
|
|
|
static prepareEsquive(actor) {
|
|
const esquives = actor.getCompetences("Esquive")
|
|
if (esquives.length > 0) {
|
|
const esquive = esquives[0]
|
|
return {
|
|
name: esquive.name,
|
|
niveau: esquive.system.niveau,
|
|
competence: esquive
|
|
}
|
|
}
|
|
return undefined
|
|
}
|
|
|
|
static prepareSorts(actor) {
|
|
const codeVoies = Mapping.getCompetencesCategorie(actor, CATEGORIES_DRACONIC)
|
|
.map(it => RdDItemSort.getCodeVoie(it.name))
|
|
|
|
return actor.itemTypes[ITEM_TYPES.sort].map(it => Mapping.prepareSort(it, codeVoies))
|
|
.sort(Misc.ascending(it => `${it.voie} : ${it.description}`))
|
|
}
|
|
|
|
static prepareSort(sort, voies) {
|
|
return {
|
|
voie: RdDItemSort.getCode(sort, voies),
|
|
description: Mapping.descriptionSort(sort),
|
|
bonus: Mapping.bonusCase(sort)
|
|
}
|
|
}
|
|
|
|
static descriptionSort(sort) {
|
|
const ptSeuil = Array(sort.system.coutseuil).map(it => '*')
|
|
const caseTMR = sort.system.caseTMRspeciale.length > 0 ? Mapping.toVar(sort.system.caseTMRspeciale) : Misc.upperFirst(TMRType[sort.system.caseTMR].name)
|
|
const coutReve = 'r' + RdDItemSort.addSpaceToNonNumeric(sort.system.ptreve)
|
|
const diff = 'R' + RdDItemSort.addSpaceToNonNumeric(sort.system.difficulte)
|
|
return `${sort.name}${ptSeuil} (${caseTMR}) ${diff} ${coutReve}`
|
|
}
|
|
|
|
static bonusCase(sort) {
|
|
const list = RdDItemSort.stringToBonuscases(sort.system.bonuscase).sort(Misc.descending(it => it.bonus))
|
|
if (list.length > 0) {
|
|
const bonus = list[0]
|
|
return `+${bonus.bonus}% en ${bonus.case}`
|
|
}
|
|
return ''
|
|
}
|
|
|
|
static getDescription(actor) {
|
|
const sexe = actor.system.sexe
|
|
const sexeFeminin = sexe.length > 0 && sexe.charAt(0).toLowerCase() == 'f' ? 'Née' : 'Né'
|
|
const race = ['', 'humain'].includes(Grammar.toLowerCaseNoAccent(actor.system.race)) ? '' : (actor.system.race + ' ')
|
|
const heure = actor.system.heure
|
|
const hn = `${sexeFeminin} à l'heure ${RdDTimestamp.definition(heure).avecArticle}`
|
|
const age = actor.system.age ? `${actor.system.age} ans` : undefined
|
|
const taille = actor.system.taille
|
|
const poids = actor.system.poids
|
|
const cheveux = actor.system.cheveux ? `cheveux ${actor.system.cheveux}` : undefined
|
|
const yeux = actor.system.yeux ? `yeux ${actor.system.yeux}` : undefined
|
|
const beaute = actor.system.beaute ? `beauté ${actor.system.beaute}` : undefined
|
|
const list = [race, hn, age, taille, poids, cheveux, yeux, beaute]
|
|
return Misc.join(list.filter(it => it), ', ')
|
|
}
|
|
|
|
static getArmure(actor, context) {
|
|
return context.armure?.name ?? ''
|
|
}
|
|
|
|
static getProtectionArmure(actor, context) {
|
|
const naturelle = Number(actor.system.attributs.protection.value)
|
|
if (context?.armure?.protection == undefined) {
|
|
return naturelle
|
|
}
|
|
if (Number.isNumeric(context?.armure?.protection)) {
|
|
return Number(context?.armure?.protection ?? 0) + naturelle
|
|
}
|
|
return context?.armure.protection + (naturelle > 0 ? `+${naturelle}` : '')
|
|
}
|
|
|
|
static getMalusArmure(actor, context) {
|
|
return context?.armure?.malus ?? 0
|
|
}
|
|
|
|
static getEsquive(context) {
|
|
if (context.esquive) {
|
|
return Misc.toSignedString(context.esquive.niveau)
|
|
}
|
|
return ''
|
|
}
|
|
static getEsquiveArmure(context) {
|
|
if (context.esquive) {
|
|
const niveau = context.esquive.niveau + context.armure.malus
|
|
return Misc.toSignedString(niveau)
|
|
}
|
|
return ''
|
|
}
|
|
|
|
static getCompetences(actor, categories) {
|
|
const competences = Mapping.getCompetencesCategorie(actor, categories)
|
|
if (competences.length == 0) {
|
|
return ''
|
|
}
|
|
const byCategories = Mapping.competencesByCategoriesByNiveau(competences, categories)
|
|
const txtByCategories = Object.values(byCategories)
|
|
.map(it => it.competencesParNiveau)
|
|
.map(byNiveau => {
|
|
const niveaux = Object.keys(byNiveau)
|
|
.map(it => Number(it)).sort(Misc.ascending())
|
|
if (niveaux.length == 0) {
|
|
return ''
|
|
}
|
|
const txtCategorieByNiveau = niveaux.map(niveau => {
|
|
const names = Misc.join(byNiveau[niveau].map(it => it.name).sort(Misc.ascending()), ', ')
|
|
return names + ' ' + Misc.toSignedString(niveau)
|
|
})
|
|
const txtCategorie = Misc.join(txtCategorieByNiveau, ' / ')
|
|
return txtCategorie
|
|
}).filter(it => it != '')
|
|
|
|
return Misc.join(txtByCategories, ' / ')
|
|
}
|
|
|
|
static competencesByCategoriesByNiveau(competences, categories) {
|
|
return categories.map(c => {
|
|
return {
|
|
categorie: c,
|
|
competencesParNiveau: Misc.classify(
|
|
competences.filter(comp => comp.system.categorie == c),
|
|
comp => comp.system.niveau)
|
|
}
|
|
})
|
|
}
|
|
|
|
static getArme(actor, context, part, numero) {
|
|
if (numero < context.armes.length) {
|
|
return context.armes[numero][part] ?? ''
|
|
}
|
|
return ''
|
|
}
|
|
|
|
static getCompetencesCategorie(actor, categories) {
|
|
return actor.itemTypes[ITEM_TYPES.competence]
|
|
.filter(it => categories.includes(it.system.categorie))
|
|
.filter(it => !RdDItemCompetence.isNiveauBase(it))
|
|
}
|
|
|
|
static getSort(actor, context, part, numero) {
|
|
if (numero < context.sorts.length) {
|
|
return context.sorts[numero][part]
|
|
}
|
|
return ''
|
|
}
|
|
}
|
|
|