Completed ability editor
This commit is contained in:
parent
308c2974f1
commit
1de2439a8a
BIN
db.sqlite-shm
BIN
db.sqlite-shm
Binary file not shown.
BIN
db.sqlite-wal
BIN
db.sqlite-wal
Binary file not shown.
|
|
@ -26,6 +26,18 @@ const mainStatTexts: Record<MainStat, string> = {
|
||||||
"charisma": "Charisme",
|
"charisma": "Charisme",
|
||||||
"psyche": "Psyché",
|
"psyche": "Psyché",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function abilitySpecialFeatures(type: "points" | "max", curiosity: DoubleIndex<TrainingLevel>[], value: number): number
|
||||||
|
{
|
||||||
|
if(type === 'points')
|
||||||
|
{
|
||||||
|
if(curiosity.find(e => e[0] == 7 && e[1] === 0))
|
||||||
|
return Math.max(6, value);
|
||||||
|
if(curiosity.find(e => e[0] == 7 && e[1] === 2))
|
||||||
|
return value + 1;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Icon } from '@iconify/vue/dist/iconify.js';
|
import { Icon } from '@iconify/vue/dist/iconify.js';
|
||||||
|
|
@ -71,11 +83,11 @@ const trainingPoints = computed(() => {
|
||||||
});
|
});
|
||||||
const training = computed(() => Object.entries(characterConfig.training).map(e => [e[0], getFeaturesOf(e[0] as MainStat, data.value.progress.training[e[0] as MainStat])]) as [MainStat, TrainingOption[]][])
|
const training = computed(() => Object.entries(characterConfig.training).map(e => [e[0], getFeaturesOf(e[0] as MainStat, data.value.progress.training[e[0] as MainStat])]) as [MainStat, TrainingOption[]][])
|
||||||
const maxTraining = computed(() => Object.entries(data.value.progress.training).reduce((p, v) => { p[v[0]] = v[1].reduce((_p, _v) => Math.max(_p, _v[0]) , 0); return p; }, {} as Record<MainStat, number>));
|
const maxTraining = computed(() => Object.entries(data.value.progress.training).reduce((p, v) => { p[v[0]] = v[1].reduce((_p, _v) => Math.max(_p, _v[0]) , 0); return p; }, {} as Record<MainStat, number>));
|
||||||
const trainingSpent = computed(() => Object.values(maxTraining.value).reduce((p, v) => p + v));
|
const trainingSpent = computed(() => Object.values(maxTraining.value).reduce((p, v) => p + v, 0));
|
||||||
const modifiers = computed(() => Object.entries(maxTraining.value).reduce((p, v) => { p[v[0]] = Math.floor(v[1] / 3) + (data.value.progress.modifiers ? data.value.progress.modifiers[v[0]] : 0); return p; }, {} as Record<MainStat, number>))
|
const modifiers = computed(() => Object.entries(maxTraining.value).reduce((p, v) => { p[v[0]] = Math.floor(v[1] / 3) + (data.value.progress.modifiers ? (data.value.progress.modifiers[v[0] as MainStat] ?? 0) : 0); return p; }, {} as Record<MainStat, number>))
|
||||||
const abilityPoints = computed(() => training.value.flatMap(e => e[1].filter(_e => _e.ability !== undefined)).reduce((p, v) => p + v.ability!, 0));
|
const abilityPoints = computed(() => training.value.flatMap(e => e[1].filter(_e => _e.ability !== undefined)).reduce((p, v) => p + v.ability!, 0));
|
||||||
const abilityMax = computed(() => Object.entries(characterConfig.ability).reduce((p, v) => { p[v[0]] = Math.floor(maxTraining.value[v[1].max[0]] / 3) + Math.floor(maxTraining.value[v[1].max[1]] / 3); return p; }, {} as Record<Ability, number>));
|
const abilityMax = computed(() => Object.entries(characterConfig.ability).reduce((p, v) => { p[v[0]] = abilitySpecialFeatures("max", data.value.progress.training.curiosity, Math.floor(maxTraining.value[v[1].max[0]] / 3) + Math.floor(maxTraining.value[v[1].max[1]] / 3)); return p; }, {} as Record<Ability, number>));
|
||||||
const abilitySpent = computed(() => Object.values(data.value.progress.abilities ?? {}).reduce((p, v) => p + v[1], 0));
|
const abilitySpent = computed(() => Object.values(data.value.progress.abilities ?? {}).reduce((p, v) => p + v[0], 0));
|
||||||
|
|
||||||
if(id !== 'new')
|
if(id !== 'new')
|
||||||
{
|
{
|
||||||
|
|
@ -167,6 +179,11 @@ function updateLevel()
|
||||||
}
|
}
|
||||||
async function save(leave: boolean)
|
async function save(leave: boolean)
|
||||||
{
|
{
|
||||||
|
if(data.value.name === '' || data.value.progress.race.index === undefined || data.value.progress.race.index === -1)
|
||||||
|
{
|
||||||
|
add({ title: 'Données manquantes', content: "Merci de saisir un nom et une race avant de pouvoir enregistrer votre personnage", type: 'error', duration: 25000, timer: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(id === 'new')
|
if(id === 'new')
|
||||||
{
|
{
|
||||||
id = await useRequestFetch()(`/api/character`, {
|
id = await useRequestFetch()(`/api/character`, {
|
||||||
|
|
@ -263,46 +280,10 @@ useShortcuts({
|
||||||
<Icon icon="radix-icons:caret-right" class="w-6 h-6 border border-light-30 dark:border-dark-30 cursor-pointer" @click="() => trainingTab = clamp(trainingTab + 1, 0, 6)" />
|
<Icon icon="radix-icons:caret-right" class="w-6 h-6 border border-light-30 dark:border-dark-30 cursor-pointer" @click="() => trainingTab = clamp(trainingTab + 1, 0, 6)" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-4 relative" :style="`left: calc(calc(-100% - 1em) * ${trainingTab}); transition: left .5s ease;`">
|
<div class="flex gap-4 relative" :style="`left: calc(calc(-100% - 1em) * ${trainingTab}); transition: left .5s ease;`">
|
||||||
<div class="flex w-full flex-shrink-0 flex-col gap-2 relative">
|
<div class="flex w-full flex-shrink-0 flex-col gap-2 relative" v-for="(text, stat) of mainStatTexts">
|
||||||
<div class="sticky top-1 left-16 py-1 px-3 bg-light-0 dark:bg-dark-0 z-10 text-xl font-bold self-start border border-light-30 dark:border-dark-30">Force<span v-if="maxTraining.strength >= 0">: Niveau {{ maxTraining.strength }} (+{{ modifiers.strength }})</span></div>
|
<div class="sticky top-1 left-16 py-1 px-3 bg-light-0 dark:bg-dark-0 z-10 text-xl font-bold self-start border border-light-30 dark:border-dark-30">{{ text }}<span v-if="maxTraining[stat] >= 0">: Niveau {{ maxTraining[stat] }} (+{{ modifiers[stat] }})</span></div>
|
||||||
<div class="flex flex-row gap-4 justify-center" v-for="(level, index) of characterConfig.training.strength" :class="{ 'opacity-30': index > maxTraining.strength + 1 }">
|
<div class="flex flex-row gap-4 justify-center" v-for="(level, index) of characterConfig.training[stat]" :class="{ 'opacity-30': index > maxTraining[stat] + 1 }">
|
||||||
<div class="border border-light-40 dark:border-dark-40 cursor-pointer px-2 py-1 w-1/3" v-for="(option, i) of level" @click="switchTrainingOption('strength', index as TrainingLevel, i)" :class="{ 'hover:border-light-60 dark:hover:border-dark-60': index <= maxTraining.strength + 1, '!border-accent-blue bg-accent-blue bg-opacity-20': index == 0 || (data.progress.training.strength?.some(e => e[0] == index && e[1] === i) ?? false) }"><MarkdownRenderer :proses="{ 'a': PreviewA }" :content="option.description.map(e => e.text).join('\n')" /></div>
|
<div class="border border-light-40 dark:border-dark-40 cursor-pointer px-2 py-1 w-1/3" v-for="(option, i) of level" @click="switchTrainingOption(stat, index as TrainingLevel, i)" :class="{ 'hover:border-light-60 dark:hover:border-dark-60': index <= maxTraining[stat] + 1, '!border-accent-blue bg-accent-blue bg-opacity-20': index == 0 || (data.progress.training[stat]?.some(e => e[0] == index && e[1] === i) ?? false) }"><MarkdownRenderer :proses="{ 'a': PreviewA }" :content="option.description.map(e => e.text).join('\n')" /></div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex w-full flex-shrink-0 flex-col gap-2 relative">
|
|
||||||
<div class="sticky top-1 left-16 py-1 px-3 bg-light-0 dark:bg-dark-0 z-10 text-xl font-bold self-start border border-light-30 dark:border-dark-30">Dextérité<span v-if="maxTraining.dexterity >= 0">: Niveau {{ maxTraining.dexterity }} (+{{ modifiers.dexterity }})</span></div>
|
|
||||||
<div class="flex flex-row gap-4 justify-center" v-for="(level, index) of characterConfig.training.dexterity" :class="{ 'opacity-30': index > maxTraining.dexterity + 1 }">
|
|
||||||
<div class="border border-light-40 dark:border-dark-40 cursor-pointer px-2 py-1 w-1/3" v-for="(option, i) of level" @click="switchTrainingOption('dexterity', index as TrainingLevel, i)" :class="{ 'hover:border-light-60 dark:hover:border-dark-60': index <= maxTraining.dexterity + 1, '!border-accent-blue bg-accent-blue bg-opacity-20': index == 0 || (data.progress.training.dexterity?.some(e => e[0] == index && e[1] === i) ?? false) }"><MarkdownRenderer :proses="{ 'a': PreviewA }" :content="option.description.map(e => e.text).join('\n')" /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex w-full flex-shrink-0 flex-col gap-2 relative">
|
|
||||||
<div class="sticky top-1 left-16 py-1 px-3 bg-light-0 dark:bg-dark-0 z-10 text-xl font-bold self-start border border-light-30 dark:border-dark-30">Constitution<span v-if="maxTraining.constitution >= 0">: Niveau {{ maxTraining.constitution }} (+{{ modifiers.constitution }})</span></div>
|
|
||||||
<div class="flex flex-row gap-4 justify-center" v-for="(level, index) of characterConfig.training.constitution" :class="{ 'opacity-30': index > maxTraining.constitution + 1 }">
|
|
||||||
<div class="border border-light-40 dark:border-dark-40 cursor-pointer px-2 py-1 w-1/3" v-for="(option, i) of level" @click="switchTrainingOption('constitution', index as TrainingLevel, i)" :class="{ 'hover:border-light-60 dark:hover:border-dark-60': index <= maxTraining.constitution + 1, '!border-accent-blue bg-accent-blue bg-opacity-20': index == 0 || (data.progress.training.constitution?.some(e => e[0] == index && e[1] === i) ?? false) }"><MarkdownRenderer :proses="{ 'a': PreviewA }" :content="option.description.map(e => e.text).join('\n')" /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex w-full flex-shrink-0 flex-col gap-2 relative">
|
|
||||||
<div class="sticky top-1 left-16 py-1 px-3 bg-light-0 dark:bg-dark-0 z-10 text-xl font-bold self-start border border-light-30 dark:border-dark-30">Intelligence<span v-if="maxTraining.intelligence >= 0">: Niveau {{ maxTraining.intelligence }} (+{{ modifiers.intelligence }})</span></div>
|
|
||||||
<div class="flex flex-row gap-4 justify-center" v-for="(level, index) of characterConfig.training.intelligence" :class="{ 'opacity-30': index > maxTraining.intelligence + 1 }">
|
|
||||||
<div class="border border-light-40 dark:border-dark-40 cursor-pointer px-2 py-1 w-1/3" v-for="(option, i) of level" @click="switchTrainingOption('intelligence', index as TrainingLevel, i)" :class="{ 'hover:border-light-60 dark:hover:border-dark-60': index <= maxTraining.intelligence + 1, '!border-accent-blue bg-accent-blue bg-opacity-20': index == 0 || (data.progress.training.intelligence?.some(e => e[0] == index && e[1] === i) ?? false) }"><MarkdownRenderer :proses="{ 'a': PreviewA }" :content="option.description.map(e => e.text).join('\n')" /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex w-full flex-shrink-0 flex-col gap-2 relative">
|
|
||||||
<div class="sticky top-1 left-16 py-1 px-3 bg-light-0 dark:bg-dark-0 z-10 text-xl font-bold self-start border border-light-30 dark:border-dark-30">Curiosité<span v-if="maxTraining.curiosity >= 0">: Niveau {{ maxTraining.curiosity }} (+{{ modifiers.curiosity }})</span></div>
|
|
||||||
<div class="flex flex-row gap-4 justify-center" v-for="(level, index) of characterConfig.training.curiosity" :class="{ 'opacity-30': index > maxTraining.curiosity + 1 }">
|
|
||||||
<div class="border border-light-40 dark:border-dark-40 cursor-pointer px-2 py-1 w-1/3" v-for="(option, i) of level" @click="switchTrainingOption('curiosity', index as TrainingLevel, i)" :class="{ 'hover:border-light-60 dark:hover:border-dark-60': index <= maxTraining.curiosity + 1, '!border-accent-blue bg-accent-blue bg-opacity-20': index == 0 || (data.progress.training.curiosity?.some(e => e[0] == index && e[1] === i) ?? false) }"><MarkdownRenderer :proses="{ 'a': PreviewA }" :content="option.description.map(e => e.text).join('\n')" /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex w-full flex-shrink-0 flex-col gap-2 relative">
|
|
||||||
<div class="sticky top-1 left-16 py-1 px-3 bg-light-0 dark:bg-dark-0 z-10 text-xl font-bold self-start border border-light-30 dark:border-dark-30">Charisme<span v-if="maxTraining.charisma >= 0">: Niveau {{ maxTraining.charisma }} (+{{ modifiers.charisma }})</span></div>
|
|
||||||
<div class="flex flex-row gap-4 justify-center" v-for="(level, index) of characterConfig.training.charisma" :class="{ 'opacity-30': index > maxTraining.charisma + 1 }">
|
|
||||||
<div class="border border-light-40 dark:border-dark-40 cursor-pointer px-2 py-1 w-1/3" v-for="(option, i) of level" @click="switchTrainingOption('charisma', index as TrainingLevel, i)" :class="{ 'hover:border-light-60 dark:hover:border-dark-60': index <= maxTraining.charisma + 1, '!border-accent-blue bg-accent-blue bg-opacity-20': index == 0 || (data.progress.training.charisma?.some(e => e[0] == index && e[1] === i) ?? false) }"><MarkdownRenderer :proses="{ 'a': PreviewA }" :content="option.description.map(e => e.text).join('\n')" /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex w-full flex-shrink-0 flex-col gap-2 relative">
|
|
||||||
<div class="sticky top-1 left-16 py-1 px-3 bg-light-0 dark:bg-dark-0 z-10 text-xl font-bold self-start border border-light-30 dark:border-dark-30">Psyché<span v-if="maxTraining.psyche >= 0">: Niveau {{ maxTraining.psyche }} (+{{ modifiers.psyche }})</span></div>
|
|
||||||
<div class="flex flex-row gap-4 justify-center" v-for="(level, index) of characterConfig.training.psyche" :class="{ 'opacity-30': index > maxTraining.psyche + 1 }">
|
|
||||||
<div class="border border-light-40 dark:border-dark-40 cursor-pointer px-2 py-1 w-1/3" v-for="(option, i) of level" @click="switchTrainingOption('psyche', index as TrainingLevel, i)" :class="{ 'hover:border-light-60 dark:hover:border-dark-60': index <= maxTraining.psyche + 1, '!border-accent-blue bg-accent-blue bg-opacity-20': index == 0 || (data.progress.training.psyche?.some(e => e[0] == index && e[1] === i) ?? false) }"><MarkdownRenderer :proses="{ 'a': PreviewA }" :content="option.description.map(e => e.text).join('\n')" /></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -314,12 +295,14 @@ useShortcuts({
|
||||||
<span class="font-bold text-xl">Compétences</span>
|
<span class="font-bold text-xl">Compétences</span>
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
<div class="flex flex-col gap-2 px-4">
|
<div class="flex flex-col gap-2 max-h-[50vh] px-4 relative overflow-y-auto">
|
||||||
<span class="text-xl -mx-2" :class="{ 'text-light-red dark:text-dark-red': (abilityPoints ?? 0) < abilitySpent }">Points d'entrainement restants: {{ (abilityPoints ?? 0) - abilitySpent }}</span>
|
<div class="sticky top-0 py-2 bg-light-0 dark:bg-dark-0 z-10 flex justify-between">
|
||||||
|
<span class="text-xl -mx-2" :class="{ 'text-light-red dark:text-dark-red': (abilityPoints ?? 0) < abilitySpent }">Points d'entrainement restants: {{ (abilityPoints ?? 0) - abilitySpent }}</span>
|
||||||
|
</div>
|
||||||
<div v-for="(ability, index) of characterConfig.ability" class="grid grid-cols-10 gap-4 items-center">
|
<div v-for="(ability, index) of characterConfig.ability" class="grid grid-cols-10 gap-4 items-center">
|
||||||
<span class="text-lg col-span-2">{{ ability.name }}</span>
|
<span class="text-lg col-span-2">{{ ability.name }}</span>
|
||||||
<span class="text-sm text-light-70 dark:text-dark-70 col-span-2">({{ mainStatTexts[ability.max[0]] }} + {{ mainStatTexts[ability.max[1]] }})</span>
|
<span class="text-sm text-light-70 dark:text-dark-70 col-span-2">({{ mainStatTexts[ability.max[0]] }} + {{ mainStatTexts[ability.max[1]] }})</span>
|
||||||
<NumberFieldRoot :min="0" :max="20" :default-value="data.progress.abilities[index] ? data.progress.abilities[index][0] : 0" @update:model-value="(value) => { data.progress.abilities[index] = [value, data.progress.abilities[index] ? data.progress.abilities[index][1] : 0]; console.log(abilitySpent) }" class="flex justify-center border border-light-35 dark:border-dark-35 bg-light-20 dark:bg-dark-20 data-[disabled]:border-light-20 dark:data-[disabled]:border-dark-20 data-[disabled]:bg-light-20 dark:data-[disabled]:bg-dark-20
|
<NumberFieldRoot :min="0" :max="abilityMax[index]" :default-value="data.progress.abilities[index] ? data.progress.abilities[index][0] : 0" @update:model-value="(value) => { data.progress.abilities[index] = [value, data.progress.abilities[index] ? data.progress.abilities[index][1] : 0]; console.log(abilitySpent) }" class="flex justify-center border border-light-35 dark:border-dark-35 bg-light-20 dark:bg-dark-20 data-[disabled]:border-light-20 dark:data-[disabled]:border-dark-20 data-[disabled]:bg-light-20 dark:data-[disabled]:bg-dark-20
|
||||||
data-[disabled]:text-light-70 dark:data-[disabled]:text-dark-70 hover:border-light-50 dark:hover:border-dark-50 has-[:focus]:shadow-raw transition-[box-shadow] has-[:focus]:shadow-light-40 dark:has-[:focus]:shadow-dark-40">
|
data-[disabled]:text-light-70 dark:data-[disabled]:text-dark-70 hover:border-light-50 dark:hover:border-dark-50 has-[:focus]:shadow-raw transition-[box-shadow] has-[:focus]:shadow-light-40 dark:has-[:focus]:shadow-dark-40">
|
||||||
<NumberFieldInput class="tabular-nums w-20 bg-transparent px-3 py-1 outline-none caret-light-50 dark:caret-dark-50" />
|
<NumberFieldInput class="tabular-nums w-20 bg-transparent px-3 py-1 outline-none caret-light-50 dark:caret-dark-50" />
|
||||||
</NumberFieldRoot>
|
</NumberFieldRoot>
|
||||||
|
|
@ -328,7 +311,6 @@ useShortcuts({
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Collapsible>
|
</Collapsible>
|
||||||
<div class="h-[50vh]"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -96,6 +96,12 @@ const { data: character, status, error } = await useAsyncData(() => useRequestFe
|
||||||
<span>Sorts de savoir: <span class="font-bold">{{ character.spellranks.knowledge }}</span></span>
|
<span>Sorts de savoir: <span class="font-bold">{{ character.spellranks.knowledge }}</span></span>
|
||||||
<span>Sorts d'instinct: <span class="font-bold">{{ character.spellranks.instinct }}</span></span>
|
<span>Sorts d'instinct: <span class="font-bold">{{ character.spellranks.instinct }}</span></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-lg font-semibold border-b border-light-30 dark:border-dark-30 mb-2">Compétences</span>
|
||||||
|
<div class="grid grid-cols-3 gap-1">
|
||||||
|
<div class="flex flex-col px-2 items-center" v-for="(value, ability) of character.abilities"><span class="font-bold">+{{ value }}</span><span>{{ config.ability[ability].name }}</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-1 flex-col border-l border-light-30 dark:border-dark-30 ps-8 gap-4 py-8 max-w-[80rem]">
|
<div class="flex flex-1 flex-col border-l border-light-30 dark:border-dark-30 ps-8 gap-4 py-8 max-w-[80rem]">
|
||||||
<div class="grid grid-cols-3 gap-2">
|
<div class="grid grid-cols-3 gap-2">
|
||||||
|
|
|
||||||
|
|
@ -135,23 +135,23 @@ function compileCharacter(character: Character & { username?: string }): Compile
|
||||||
misc: [],
|
misc: [],
|
||||||
},
|
},
|
||||||
abilities: {
|
abilities: {
|
||||||
athletics: [0, 0],
|
athletics: 0,
|
||||||
acrobatics: [0, 0],
|
acrobatics: 0,
|
||||||
intimidation: [0, 0],
|
intimidation: 0,
|
||||||
sleightofhand: [0, 0],
|
sleightofhand: 0,
|
||||||
stealth: [0, 0],
|
stealth: 0,
|
||||||
survival: [0, 0],
|
survival: 0,
|
||||||
investigation: [0, 0],
|
investigation: 0,
|
||||||
history: [0, 0],
|
history: 0,
|
||||||
religion: [0, 0],
|
religion: 0,
|
||||||
arcana: [0, 0],
|
arcana: 0,
|
||||||
understanding: [0, 0],
|
understanding: 0,
|
||||||
perception: [0, 0],
|
perception: 0,
|
||||||
performance: [0, 0],
|
performance: 0,
|
||||||
medecine: [0, 0],
|
medecine: 0,
|
||||||
persuasion: [0, 0],
|
persuasion: 0,
|
||||||
animalhandling: [0, 0],
|
animalhandling: 0,
|
||||||
deception: [0, 0]
|
deception: 0
|
||||||
},
|
},
|
||||||
spellslots: 0,
|
spellslots: 0,
|
||||||
spellranks: {
|
spellranks: {
|
||||||
|
|
@ -195,14 +195,15 @@ function compileCharacter(character: Character & { username?: string }): Compile
|
||||||
|
|
||||||
features.forEach(e => e[1].forEach((_e, i) => applyTrainingOption(e[0], _e, compiled, i === e[1].length - 1)));
|
features.forEach(e => e[1].forEach((_e, i) => applyTrainingOption(e[0], _e, compiled, i === e[1].length - 1)));
|
||||||
specialFeatures(compiled, character.progress.training);
|
specialFeatures(compiled, character.progress.training);
|
||||||
|
|
||||||
|
Object.entries(character.progress.abilities).forEach(e => compiled.abilities[e[0]] += e[1][0]);
|
||||||
|
|
||||||
return compiled;
|
return compiled;
|
||||||
}
|
}
|
||||||
function applyTrainingOption(stat: MainStat, option: TrainingOption, character: CompiledCharacter, last: boolean)
|
function applyTrainingOption(stat: MainStat, option: TrainingOption, character: CompiledCharacter, last: boolean)
|
||||||
{
|
{
|
||||||
if(option.health) character.health += option.health;
|
if(option.health) character.health += option.health;
|
||||||
if(option.mana) character.mana += option.mana;
|
if(option.mana) character.mana += option.mana;
|
||||||
if(option.modifier) option.modifier.forEach(e => character.modifier[e[0]] += e[1]);
|
|
||||||
if(option.ability) option.ability.forEach(e => character.abilities[e[0]]![0] += e[1]);
|
|
||||||
if(option.mastery) character.mastery[option.mastery]++;
|
if(option.mastery) character.mastery[option.mastery]++;
|
||||||
if(option.speed) character.speed = option.speed;
|
if(option.speed) character.speed = option.speed;
|
||||||
if(option.initiative) character.initiative += option.initiative;
|
if(option.initiative) character.initiative += option.initiative;
|
||||||
|
|
|
||||||
|
|
@ -1720,7 +1720,8 @@
|
||||||
"disposable": false,
|
"disposable": false,
|
||||||
"replaced": true
|
"replaced": true
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"ability": 6
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"1": [
|
"1": [
|
||||||
|
|
@ -1735,7 +1736,8 @@
|
||||||
"disposable": false,
|
"disposable": false,
|
||||||
"replaced": true
|
"replaced": true
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"ability": 3
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"2": [
|
"2": [
|
||||||
|
|
@ -1745,7 +1747,8 @@
|
||||||
"text": "+5 points de compétence.",
|
"text": "+5 points de compétence.",
|
||||||
"disposable": true
|
"disposable": true
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"ability": 5
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"3": [
|
"3": [
|
||||||
|
|
@ -1755,7 +1758,8 @@
|
||||||
"text": "+3 points de compétence.",
|
"text": "+3 points de compétence.",
|
||||||
"disposable": true
|
"disposable": true
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"ability": 3
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"4": [
|
"4": [
|
||||||
|
|
@ -1765,7 +1769,8 @@
|
||||||
"text": "+4 points de compétence.",
|
"text": "+4 points de compétence.",
|
||||||
"disposable": true
|
"disposable": true
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"ability": 4
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"5": [
|
"5": [
|
||||||
|
|
@ -1799,7 +1804,8 @@
|
||||||
"text": "+3 points de compétence.",
|
"text": "+3 points de compétence.",
|
||||||
"disposable": true
|
"disposable": true
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"ability": 3
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"6": [
|
"6": [
|
||||||
|
|
@ -1822,7 +1828,8 @@
|
||||||
"text": "+1 point de compétence.",
|
"text": "+1 point de compétence.",
|
||||||
"disposable": false
|
"disposable": false
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"ability": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": [
|
"description": [
|
||||||
|
|
@ -1830,7 +1837,8 @@
|
||||||
"text": "+3 points de compétence.",
|
"text": "+3 points de compétence.",
|
||||||
"disposable": true
|
"disposable": true
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"ability": 3
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"7": [
|
"7": [
|
||||||
|
|
@ -1838,13 +1846,14 @@
|
||||||
"description": [
|
"description": [
|
||||||
{
|
{
|
||||||
"text": "Le maximum de toutes les compétences est de 6 points, sauf s'il est déjà supérieur.",
|
"text": "Le maximum de toutes les compétences est de 6 points, sauf s'il est déjà supérieur.",
|
||||||
"disposable": false
|
"disposable": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "+2 points de compétence.",
|
"text": "+2 points de compétence.",
|
||||||
"disposable": true
|
"disposable": true
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"ability": 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": [
|
"description": [
|
||||||
|
|
@ -1858,13 +1867,14 @@
|
||||||
"description": [
|
"description": [
|
||||||
{
|
{
|
||||||
"text": "Le maximum de toutes les compétences augmente de 1 point.",
|
"text": "Le maximum de toutes les compétences augmente de 1 point.",
|
||||||
"disposable": false
|
"disposable": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "+2 points de compétence.",
|
"text": "+2 points de compétence.",
|
||||||
"disposable": true
|
"disposable": true
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"ability": 2
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"8": [
|
"8": [
|
||||||
|
|
@ -1890,7 +1900,8 @@
|
||||||
"text": "+4 points de compétence.",
|
"text": "+4 points de compétence.",
|
||||||
"disposable": true
|
"disposable": true
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"ability": 4
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"9": [
|
"9": [
|
||||||
|
|
@ -1942,7 +1953,8 @@
|
||||||
"text": "+4 points de compétence.",
|
"text": "+4 points de compétence.",
|
||||||
"disposable": true
|
"disposable": true
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"ability": 4
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"11": [
|
"11": [
|
||||||
|
|
@ -1968,7 +1980,8 @@
|
||||||
"text": "+4 points de compétence.",
|
"text": "+4 points de compétence.",
|
||||||
"disposable": true
|
"disposable": true
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"ability": 4
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"12": [
|
"12": [
|
||||||
|
|
@ -2020,7 +2033,8 @@
|
||||||
"text": "+5 points de compétence.",
|
"text": "+5 points de compétence.",
|
||||||
"disposable": true
|
"disposable": true
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"ability": 5
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"14": [
|
"14": [
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ export type CompiledCharacter = {
|
||||||
};
|
};
|
||||||
|
|
||||||
modifier: Record<MainStat, number>;
|
modifier: Record<MainStat, number>;
|
||||||
abilities: Partial<Record<Ability, [number, number]>>;
|
abilities: Partial<Record<Ability, number>>;
|
||||||
level: number;
|
level: number;
|
||||||
features: Record<Category, string[]>; //Currently: List of training option as text. TODO: Update to a more complex structure later
|
features: Record<Category, string[]>; //Currently: List of training option as text. TODO: Update to a more complex structure later
|
||||||
};
|
};
|
||||||
Loading…
Reference in New Issue