import useDatabase from '~/composables/useDatabase'; import { type Character, type CharacterConfig, type CompiledCharacter, type DoubleIndex, type Level, type MainStat, type TrainingLevel, type TrainingOption } from '~/types/character'; import characterData from '#shared/character-config.json'; import { group } from '#shared/general.util'; import { defaultCharacter, MAIN_STATS } from '#shared/character.util'; export default defineCachedEventHandler(async (e) => { const id = getRouterParam(e, "id"); if(!id) { setResponseStatus(e, 400); return; } const db = useDatabase(); const character = db.query.characterTable.findFirst({ with: { abilities: true, levels: true, modifiers: true, spells: true, training: true, user: { columns: { username: true } } }, where: (character, { eq }) => eq(character.id, parseInt(id, 10)), }).sync(); if(character !== undefined) { return compileCharacter(Object.assign(defaultCharacter, { id: character.id, name: character.name, people: character.people, level: character.level, aspect: character.aspect, notes: character.notes, health: character.health, mana: character.mana, training: character.training.reduce((p, v) => { if(!(v.stat in p)) p[v.stat] = []; p[v.stat].push([v.level as TrainingLevel, v.choice]); return p; }, {} as Record[]>), leveling: character.levels.map(e => [e.level as Level, e.choice] as DoubleIndex), abilities: group(character.abilities.map(e => ({ ...e, value: [e.value, e.max] as [number, number] })), "ability", "value"), spells: character.spells.map(e => e.value), modifiers: group(character.modifiers, "modifier", "value"), owner: character.owner, username: character.user.username, visibility: character.visibility, } as Character) as Character); } setResponseStatus(e, 404); return; }, { name: "character", getKey: (e) => getRouterParam(e, "id") || 'error' }); function compileCharacter(character: Character & { username?: string }): CompiledCharacter { const config = characterData as CharacterConfig; const race = character.people !== undefined ? config.peoples[character.people] : undefined; const raceOptions = race ? character.leveling!.map(e => race.options[e[0]][e[1]]) : []; const features = Object.entries(config.training).map(e => [e[0], getFeaturesOf(e[0] as MainStat, character.training[e[0] as MainStat])]) as [MainStat, TrainingOption[]][]; const compiled: CompiledCharacter = { id: character.id, owner: character.owner, username: character.username, name: character.name, health: raceOptions.reduce((p, v) => p + (v.health ?? 0), 0), mana: raceOptions.reduce((p, v) => p + (v.mana ?? 0), 0), race: character.people!, modifier: features.map(e => [e[0], Math.floor((e[1].length - 1) / 3) + (character.modifiers[e[0]] ?? 0)] as [MainStat, number]).reduce((p, v) => { p[v[0]] = v[1]; return p }, {} as Record), level: character.level, values: { health: character.health, mana: character.mana }, features: { action: [], reaction: [], freeaction: [], passive: [], }, abilities: { athletics: 0, acrobatics: 0, intimidation: 0, sleightofhand: 0, stealth: 0, survival: 0, investigation: 0, history: 0, religion: 0, arcana: 0, understanding: 0, perception: 0, performance: 0, medecine: 0, persuasion: 0, animalhandling: 0, deception: 0 }, spellslots: 0, artslots: 0, spellranks: { instinct: 0, knowledge: 0, precision: 0, arts: 0, }, spells: character.spells ?? [], speed: false, defense: { hardcap: Infinity, static: 6, activeparry: 0, activedodge: 0, passiveparry: 0, passivedodge: 0, }, mastery: { strength: 0, dexterity: 0, shield: 0, armor: 0, multiattack: 1, magicpower: 0, magicspeed: 0, magicelement: 0, magicinstinct: 0, }, resistance: {},//Object.fromEntries(MAIN_STATS.map(e => [e as MainStat, [0, 0]])) as Record, initiative: 0, aspect: "", notes: character.notes ?? "", }; //features.forEach(e => e[1].forEach(_e => _e.features?.forEach(f => applyFeature(compiled, f)))); return compiled; } export function getFeaturesOf(stat: MainStat, progression: DoubleIndex[]): TrainingOption[] { const config = characterData as CharacterConfig; return progression.map(e => config.training[stat][e[0]][e[1]]); }