import { and, eq } from 'drizzle-orm'; import useDatabase from '~/composables/useDatabase'; import { characterTable } from '~/db/schema'; import type { Ability, Character, CharacterConfig, CompiledCharacter, DoubleIndex, Feature, MainStat, TrainingLevel, TrainingOption } from '~/types/character'; import characterData from '#shared/character-config.json'; import { users } from '~/drizzle/schema'; export default defineEventHandler(async (e) => { const id = getRouterParam(e, "id"); if(!id) { setResponseStatus(e, 400); return; } const db = useDatabase(); const character = db.select({ id: characterTable.id, name: characterTable.name, progress: characterTable.progress, owner: characterTable.owner, username: users.username }).from(characterTable).leftJoin(users, eq(characterTable.owner, users.id)).where(and(eq(characterTable.id, parseInt(id)))).get(); if(character !== undefined) { return compileCharacter(character as Character & { username: string }); } setResponseStatus(e, 404); return; }/* , { name: "character", getKey: (e) => getRouterParam(e, "id") || 'error' } */); /* Athlétisme La capacité à effectuer un acte physique intense ou prolongé. Permet de pousser, contraindre, nager, courir. Force + Constitution. Acrobatique La capacité à se mouvoir avec souplesse sous la contrainte. Permet d'escalader, d'enjamber, de sauter. Force + Dextérité. Intimidation La capacité à intimider et inspirer la crainte. Force + Charisme. Doigté La capacité à faire des actions précises avec ses mains. Permet de voler à la tire, de crocheter. Dextérité + Dextérité. Discrétion La capacité à dissimuler sa présence. Permet de se cacher, de se mouvoir sans bruit. Dextérité + Dextérité. Survie La capacité à survivre dans des conditions difficiles. Permet de pister, de collecter de la nourriture, de retrouver son chemin. Constitution + Psyché. Enquête La capacité à demander au MJ de l'aide parce que vous puez la merde. Intelligence + Curiosité. Histoire La capacité à connaitre le passé du monde. Intelligence + Curiosité. Religion La capacité a connaitre les pratiques et les coutumes religieuses. Intelligence + Curiosité. Arcanes La capacité à comprendre et percevoir la magie. Permet de comprendre un sort en cours, de détecter de la magie. Intelligence + Psyché. Compréhension La capacité à déterminer les intentions des interlocuteurs. Permet de déceler des mensonges, de l'influence. Intelligence + Charisme. Perception La capacité à observer le monde à travers ces sens. Permet d'observer, d'entendre, de sentir. Curiosité + Curiosité. Représentation La capacité à se mettre en scène et à utiliser les arts. Permet de se produire en spectacle, de jouer d'un instrument, de chanter, de danser. Curiosité + Charisme. Médicine La capacité à apporter des soins. Permet de stabiliser un joueur mourant, de soigner durant un repos. Curiosité + Psyché. Persuasion Charisme + Psyché. Dressage Charisme + Psyché. Mensonge Charisme + Psyché. */ function compileCharacter(character: Character & { username?: string }): CompiledCharacter { const config = characterData as CharacterConfig; const race = character.progress.race.index !== undefined ? config.peoples[character.progress.race.index] : undefined; const raceOptions = race ? character.progress.race.progress!.map(e => race.options[e[0]][e[1]]) : []; const features = Object.entries(config.training).map(e => [e[0], getFeaturesOf(e[0] as MainStat, character.progress.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.progress.race.index ?? -1, modifier: features.map(e => [e[0], Math.floor((e[1].length - 1) / 3) + (character.progress.modifiers[e[0]] ?? 0)] as [MainStat, number]).reduce((p, v) => { p[v[0]] = v[1]; return p }, {} as Record), level: character.progress.level, features: { action: [], reaction: [], freeaction: [], misc: [], }, 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.progress.spells ?? [], speed: false, defense: { 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 }, resistance: { stun: [0, 0], bleed: [0, 0], poison: [0, 0], fear: [0, 0], influence: [0, 0], charm: [0, 0], possesion: [0, 0], precision: [0, 0], knowledge: [0, 0], instinct: [0, 0] }, initiative: 0, aspect: "", notes: character.progress.notes, }; features.forEach(e => e[1].forEach((_e, i) => applyTrainingOption(e[0], _e, compiled, i === e[1].length - 1))); specialFeatures(compiled, character.progress.training); Object.entries(character.progress.abilities).forEach(e => compiled.abilities[e[0] as Ability]! += e[1][0]); return compiled; } function applyTrainingOption(stat: MainStat, option: TrainingOption, character: CompiledCharacter, last: boolean) { if(option.health) character.health += option.health; if(option.mana) character.mana += option.mana; if(option.mastery) character.mastery[option.mastery]++; if(option.speed) character.speed = option.speed; if(option.initiative) character.initiative += option.initiative; if(option.spellrank) character.spellranks[option.spellrank]++; if(option.defense) option.defense.forEach(e => character.defense[e]++); if(option.resistance) option.resistance.forEach(e => character.resistance[e[0]][e[1] === "attack" ? 0 : 1]++); if(option.spellslot) character.spellslots += option.spellslot in character.modifier ? character.modifier[option.spellslot as MainStat] : option.spellslot as number; if(option.arts) character.artslots += option.arts in character.modifier ? character.modifier[option.arts as MainStat] : option.arts as number; if(option.spell) character.spells.push(option.spell); option.description.forEach(line => !line.disposable && (last || !line.replaced) && character.features[line.category ?? "misc"].push(line.text)); //if(option.features) option.features.forEach(e => applyFeature(e, character)); } function specialFeatures(character: CompiledCharacter, levels: Record[]>) { //Cap la défense const strengthCap3 = levels.strength.some(e => e[0] === 0); const strengthCap6 = levels.strength.some(e => e[0] === 1); const strengthUncapped = levels.strength.some(e => e[0] === 2); const dexterityCap3 = levels.dexterity.some(e => e[0] === 0); const dexterityCap3Stat = levels.dexterity.some(e => e[0] === 1); const dexterityUncapped = levels.dexterity.some(e => e[0] === 2); if(!strengthUncapped || !dexterityUncapped) { if(strengthCap6) { character.defense = { static: 6, activeparry: 0, activedodge: 0, passiveparry: 0, passivedodge: 0, }; } else if(strengthCap3 || dexterityCap3) { character.defense = { static: 3, activeparry: 0, activedodge: 0, passiveparry: 0, passivedodge: 0, }; } else if(dexterityCap3Stat) { character.defense.static = 3; } } }/* function applyFeature(feature: Feature, character: CompiledCharacter) { } */ export function getFeaturesOf(stat: MainStat, progression: DoubleIndex[]): TrainingOption[] { const config = characterData as CharacterConfig; return progression.map(e => config.training[stat][e[0]][e[1]]); }