191 lines
17 KiB
Vue
191 lines
17 KiB
Vue
<script setup lang="ts">
|
|
import config from '#shared/character-config.json';
|
|
import { Icon } from '@iconify/vue/dist/iconify.js';
|
|
import PreviewA from '~/components/prose/PreviewA.vue';
|
|
import type { SpellConfig } from '~/types/character';
|
|
import { elementTexts, spellTypeTexts, type CharacterConfig } from '~/types/character';
|
|
|
|
const characterConfig = config as CharacterConfig;
|
|
|
|
const id = useRouter().currentRoute.value.params.id;
|
|
const { user } = useUserSession();
|
|
const { add } = useToast();
|
|
|
|
const { data: character, status, error } = await useFetch(`/api/character/${id}/compiled`);
|
|
</script>
|
|
|
|
<template>
|
|
<div v-if="status === 'pending'">
|
|
<Head>
|
|
<Title>d[any] - Chargement ...</Title>
|
|
</Head>
|
|
</div>
|
|
<div v-else-if="status === 'success' && character && !error">
|
|
<Head>
|
|
<Title>d[any] - {{ character.name }}</Title>
|
|
</Head>
|
|
<div class="flex flex-row gap-4 justify-between">
|
|
<div></div>
|
|
<div class="flex lg:flex-row flex-col gap-6 items-center justify-center">
|
|
<div class="flex gap-6 items-center">
|
|
<Avatar src="" icon="radix-icons:person" size="large" />
|
|
<div class="flex flex-col">
|
|
<span class="text-xl font-bold">{{ character.name }}</span>
|
|
<span class="text-sm">De {{ character.username }}</span>
|
|
</div>
|
|
<div class="flex flex-col">
|
|
<span class="font-bold">Niveau {{ character.level }}</span>
|
|
<span>{{ character.race === -1 ? "Race inconnue" : characterConfig.peoples[character.race].name }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="flex gap-6 lg:border-l border-light-30 dark:border-dark-30 py-4 ps-4">
|
|
<span class="flex flex-row items-center gap-2">PV: {{ character.health - character.values.hp }}/{{ character.health }}</span>
|
|
<span class="flex flex-row items-center gap-2">Mana: {{ character.mana - character.values.mana }}/{{ character.mana }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="self-center">
|
|
<Tooltip side="right" message="Modifier" v-if="user && user.id === character.owner"><NuxtLink :to="{ name: 'character-id-edit', params: { id: character.id } }"><Button icon><Icon icon="radix-icons:pencil-2" /></Button></NuxtLink></Tooltip>
|
|
</div>
|
|
</div>
|
|
<div class="flex flex-1 flex-col justify-center gap-4 *:py-2">
|
|
<div class="grid 2xl:grid-cols-12 grid-cols-2 gap-4 items-center border-b border-light-30 dark:border-dark-30">
|
|
<div class="flex relative justify-between ps-4 gap-2 2xl:col-span-6 lg:col-span-2">
|
|
<div class="flex flex-col items-center"><span class="2xl:text-2xl text-xl font-bold">+{{ character.modifier.strength }}</span><span class="text-sm 2xl:text-base">Force</span></div>
|
|
<div class="flex flex-col items-center"><span class="2xl:text-2xl text-xl font-bold">+{{ character.modifier.dexterity }}</span><span class="text-sm 2xl:text-base">Dextérité</span></div>
|
|
<div class="flex flex-col items-center"><span class="2xl:text-2xl text-xl font-bold">+{{ character.modifier.constitution }}</span><span class="text-sm 2xl:text-base">Constitution</span></div>
|
|
<div class="flex flex-col items-center"><span class="2xl:text-2xl text-xl font-bold">+{{ character.modifier.intelligence }}</span><span class="text-sm 2xl:text-base">Intelligence</span></div>
|
|
<div class="flex flex-col items-center"><span class="2xl:text-2xl text-xl font-bold">+{{ character.modifier.curiosity }}</span><span class="text-sm 2xl:text-base">Curiosité</span></div>
|
|
<div class="flex flex-col items-center"><span class="2xl:text-2xl text-xl font-bold">+{{ character.modifier.charisma }}</span><span class="text-sm 2xl:text-base">Charisme</span></div>
|
|
<div class="flex flex-col items-center"><span class="2xl:text-2xl text-xl font-bold">+{{ character.modifier.psyche }}</span><span class="text-sm 2xl:text-base">Psyché</span></div>
|
|
</div>
|
|
<div class="flex relative 2xl:border-l border-light-30 dark:border-dark-30 ps-4 2xl:col-span-2">
|
|
<div class="flex flex-1 flex-row items-center justify-between">
|
|
<div class="flex flex-col px-2 items-center"><span class="text-2xl font-bold">+{{ character.initiative }}</span><span>Initiative</span></div>
|
|
<div class="flex flex-col px-2 items-center"><span class="text-2xl font-bold">{{ character.speed === false ? "Aucun déplacement" : `${character.speed} cases` }}</span><span>Course</span></div>
|
|
</div>
|
|
<!-- <div class="absolute top-0 left-0 bottom-0 right-0 bg-light-0 dark:bg-dark-0 bg-opacity-50 dark:bg-opacity-50 text-xl font-bold flex items-center justify-center">Les données secondaires arrivent bientôt.</div> -->
|
|
</div>
|
|
<div class="flex relative border-l border-light-30 dark:border-dark-30 ps-4 2xl:col-span-4">
|
|
<div class="flex flex-col px-2">
|
|
<span class="text-xl">Défense passive: <span class="text-2xl font-bold">{{ character.defense.static }}</span>/+<span class="text-2xl font-bold">{{ character.defense.passivedodge }}</span>/+<span class="text-2xl font-bold">{{ character.defense.passiveparry }}</span></span>
|
|
<span class="text-xl">Défense active: <span class="float-right">+<span class="text-2xl font-bold">{{ character.defense.activedodge }}</span>/+<span class="text-2xl font-bold">{{ character.defense.activeparry }}</span></span></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="flex flex-1 px-8">
|
|
<div class="flex flex-col pe-8 gap-4 py-8 w-80 border-r border-light-30 dark:border-dark-30">
|
|
<div class="flex flex-col">
|
|
<span class="text-lg font-semibold border-b border-light-30 dark:border-dark-30">Maitrise d'arme</span>
|
|
<div class="grid grid-cols-2 gap-x-3 gap-y-1">
|
|
<PreviewA v-if="character.mastery.strength + character.mastery.dexterity > 0" href="1. Règles/99. Annexes/4. Équipement#Les armes légères">Arme légère</PreviewA>
|
|
<PreviewA v-if="character.mastery.strength + character.mastery.dexterity > 0" href="1. Règles/99. Annexes/4. Équipement#Les armes de jet">Arme de jet</PreviewA>
|
|
<PreviewA v-if="character.mastery.strength + character.mastery.dexterity > 0" href="1. Règles/99. Annexes/4. Équipement#Les armes naturelles">Arme naturelle</PreviewA>
|
|
<PreviewA v-if="character.mastery.strength > 1" href="1. Règles/99. Annexes/4. Équipement#Les armes">Arme standard</PreviewA>
|
|
<PreviewA v-if="character.mastery.strength > 1" href="1. Règles/99. Annexes/4. Équipement#Les armes improvisées">Arme improvisée</PreviewA>
|
|
<PreviewA v-if="character.mastery.strength > 2" href="1. Règles/99. Annexes/4. Équipement#Les armes lourdes">Arme lourde</PreviewA>
|
|
<PreviewA v-if="character.mastery.strength > 3" href="1. Règles/99. Annexes/4. Équipement#Les armes à deux mains">Arme à deux mains</PreviewA>
|
|
<PreviewA v-if="character.mastery.dexterity > 0 && character.mastery.strength > 1" href="1. Règles/99. Annexes/4. Équipement#Les armes maniables">Arme maniable</PreviewA>
|
|
<PreviewA v-if="character.mastery.dexterity > 1 && character.mastery.strength > 1" href="1. Règles/99. Annexes/4. Équipement#Les armes à projectiles">Arme à projectiles</PreviewA>
|
|
<PreviewA v-if="character.mastery.dexterity > 1 && character.mastery.strength > 2" href="1. Règles/99. Annexes/4. Équipement#Les armes longues">Arme longue</PreviewA>
|
|
<PreviewA v-if="character.mastery.shield > 0" href="1. Règles/99. Annexes/4. Équipement#Les boucliers">Bouclier</PreviewA>
|
|
<PreviewA v-if="character.mastery.shield > 0 && character.mastery.strength > 3" href="1. Règles/99. Annexes/4. Équipement#Les boucliers à deux mains">Bouclier à deux mains</PreviewA>
|
|
</div>
|
|
</div>
|
|
<div v-if="character.mastery.armor > 0" class="flex flex-col">
|
|
<span class="text-lg font-semibold border-b border-light-30 dark:border-dark-30">Maitrise d'armure</span>
|
|
<div class="grid grid-cols-2 gap-x-3 gap-y-1">
|
|
<PreviewA v-if="character.mastery.armor > 0" href="1. Règles/99. Annexes/4. Équipement#Les armures légères">Armure légère</PreviewA>
|
|
<PreviewA v-if="character.mastery.armor > 1" href="1. Règles/99. Annexes/4. Équipement#Les armures">Armure standard</PreviewA>
|
|
<PreviewA v-if="character.mastery.armor > 2" href="1. Règles/99. Annexes/4. Équipement#Les armures lourdes">Armure lourde</PreviewA>
|
|
</div>
|
|
</div>
|
|
<div class="flex flex-col">
|
|
<span class="text-lg font-semibold border-b border-light-30 dark:border-dark-30">Maitrise de sorts</span>
|
|
<span>Sorts de précision: <span class="font-bold">{{ character.spellranks.precision }}</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>
|
|
</div>
|
|
<div class="flex flex-col">
|
|
<span class="text-lg font-semibold border-b border-light-30 dark:border-dark-30 mb-2 flex items-center gap-4">Résistances (Attaque/Défense) <Tooltip side="right" message="Les défenses affichées incluent déjà leur modifieur de statistique."><Icon icon="radix-icons:question-mark-circled" /></Tooltip></span>
|
|
<div class="grid grid-cols-3 gap-1">
|
|
<div class="flex flex-col px-2 items-center text-sm text-light-70 dark:text-dark-70" v-for="(value, resistance) of character.resistance"><span class="font-bold text-base text-light-100 dark:text-dark-100">+{{ value[0] }}/+{{ value[1] + character.modifier[characterConfig.resistances[resistance].statistic as MainStat] }}</span><span>{{ characterConfig.resistances[resistance].name }}</span></div>
|
|
</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 text-sm text-light-70 dark:text-dark-70" v-for="(value, ability) of character.abilities"><span class="font-bold text-base text-light-100 dark:text-dark-100">+{{ value }}</span><span>{{ characterConfig.abilities[ability].name }}</span></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<TabsRoot default-value="features" class="w-[60rem]">
|
|
<TabsList class="flex flex-row gap-4 relative px-4">
|
|
<TabsIndicator class="absolute px-8 left-0 h-[3px] bottom-0 w-[--radix-tabs-indicator-size] translate-x-[--radix-tabs-indicator-position] transition-[width,transform] duration-300 bg-accent-blue"></TabsIndicator>
|
|
<TabsTrigger value="features" class="px-2 py-1 border-b border-transparent hover:border-accent-blue">Aptitudes</TabsTrigger>
|
|
<TabsTrigger value="spells" class="px-2 py-1 border-b border-transparent hover:border-accent-blue">Sorts</TabsTrigger>
|
|
<TabsTrigger value="notes" class="px-2 py-1 border-b border-transparent hover:border-accent-blue">Notes</TabsTrigger>
|
|
</TabsList>
|
|
<TabsContent value="features">
|
|
<div class="flex flex-1 flex-col ps-8 gap-4 py-8">
|
|
<div class="grid grid-cols-3 gap-2">
|
|
<div class="flex flex-col">
|
|
<span class="text-lg font-semibold">Actions</span>
|
|
<span class="text-sm text-light-70 dark:text-dark-70">Attaquer - Saisir - Faire chuter - Déplacer - Courir - Pas de coté - Lancer un sort - S'interposer - Se transformer - Utiliser un objet - Anticiper une action - Improviser</span>
|
|
<MarkdownRenderer :content="character.features.action.join('\n')" />
|
|
</div>
|
|
<div class="flex flex-col">
|
|
<span class="text-lg font-semibold">Réactions</span>
|
|
<span class="text-sm text-light-70 dark:text-dark-70">Parade - Esquive - Saisir une opportunité - Prendre en tenaille - Intercepter - Désarmer</span>
|
|
<MarkdownRenderer :content="character.features.reaction.join('\n')" />
|
|
</div>
|
|
<div class="flex flex-col">
|
|
<span class="text-lg font-semibold">Actions libre</span>
|
|
<span class="text-sm text-light-70 dark:text-dark-70">Analyser une situation - Communiquer</span>
|
|
<MarkdownRenderer :content="character.features.freeaction.join('\n')" />
|
|
</div>
|
|
</div>
|
|
<div class="flex flex-col">
|
|
<span class="text-lg font-semibold">Aptitudes</span>
|
|
<MarkdownRenderer :content="character.features.misc.map(e => `> ${e}`).join('\n\n')" />
|
|
</div>
|
|
</div>
|
|
</TabsContent>
|
|
<TabsContent v-if="character.spells.length > 0" value="spells">
|
|
<div class="flex flex-1 flex-col ps-8 gap-4 py-8">
|
|
<div class="flex flex-col">
|
|
<div class="pb-4 px-2 mt-4 border-b last:border-none border-light-30 dark:border-dark-30 flex flex-col" v-for="spell of character.spells.map(e => characterConfig.spells.find((f: SpellConfig) => f.id === e)).filter(e => !!e)">
|
|
<div class="flex flex-row justify-between">
|
|
<span class="text-lg font-bold">{{ spell.name }}</span>
|
|
<div class="flex flex-row items-center gap-6">
|
|
<div class="flex flex-row text-sm gap-2">
|
|
<span v-for="element of spell.elements" :class="elementTexts[element].class">{{ elementTexts[element].text }}</span>
|
|
</div>
|
|
<div class="flex flex-row text-sm gap-1">
|
|
<span class="">Rang {{ spell.rank }}</span><span>/</span>
|
|
<span class="">{{ spellTypeTexts[spell.type] }}</span><span>/</span>
|
|
<span class="">{{ spell.cost }} mana</span><span>/</span>
|
|
<span class="">{{ typeof spell.speed === 'string' ? spell.speed : `${spell.speed} minutes` }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<MarkdownRenderer :content="spell.effect" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</TabsContent>
|
|
<TabsContent value="notes">
|
|
<div class="flex flex-1 flex-col ps-8 gap-4 py-8">
|
|
<MarkdownRenderer :content="character.notes" />
|
|
</div>
|
|
</TabsContent>
|
|
</TabsRoot>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else>
|
|
<Head>
|
|
<Title>d[any] - Erreur</Title>
|
|
</Head>
|
|
<div>Erreur de chargement</div>
|
|
</div>
|
|
</template> |