You've already forked obsidian-visualiser
Character creation implementation. People and training ready, still need to work on abilities and spells
This commit is contained in:
29
server/api/character.get.ts
Normal file
29
server/api/character.get.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { and, eq, sql } from 'drizzle-orm';
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { characterTable } from '~/db/schema';
|
||||
import type { Character } from '~/types/character';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const session = await getUserSession(e);
|
||||
|
||||
if(!session.user)
|
||||
{
|
||||
setResponseStatus(e, 401);
|
||||
return;
|
||||
}
|
||||
|
||||
const db = useDatabase();
|
||||
const character = db.select({
|
||||
id: characterTable.id,
|
||||
name: characterTable.name,
|
||||
progress: characterTable.progress,
|
||||
}).from(characterTable).where(eq(characterTable.owner, session.user.id)).all();
|
||||
|
||||
if(character !== undefined)
|
||||
{
|
||||
return character as Character[];
|
||||
}
|
||||
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
});
|
||||
29
server/api/character.post.ts
Normal file
29
server/api/character.post.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { characterTable } from '~/db/schema';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const body = await readBody(e);
|
||||
if(!body)
|
||||
{
|
||||
setResponseStatus(e, 400);
|
||||
return;
|
||||
}
|
||||
|
||||
const session = await getUserSession(e);
|
||||
if(!session.user || session.user.state !== 1)
|
||||
{
|
||||
setResponseStatus(e, 401);
|
||||
return;
|
||||
}
|
||||
|
||||
const db = useDatabase();
|
||||
|
||||
const id = await db.insert(characterTable).values({
|
||||
name: body.name,
|
||||
progress: body.progress,
|
||||
owner: session.user.id,
|
||||
}).returning({ id: characterTable.id });
|
||||
|
||||
setResponseStatus(e, 201);
|
||||
return id[0].id;
|
||||
});
|
||||
33
server/api/character/[id].delete.ts
Normal file
33
server/api/character/[id].delete.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { eq } from 'drizzle-orm';
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { characterTable } from '~/db/schema';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const id = getRouterParam(e, "id");
|
||||
if(!id)
|
||||
{
|
||||
setResponseStatus(e, 400);
|
||||
return;
|
||||
}
|
||||
|
||||
const db = useDatabase();
|
||||
const old = db.select({ id: characterTable.id, owner: characterTable.owner }).from(characterTable).where(eq(characterTable.id, id)).get();
|
||||
|
||||
if(!old)
|
||||
{
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
}
|
||||
|
||||
const session = await getUserSession(e);
|
||||
if(!session.user || old.owner !== session.user.id)
|
||||
{
|
||||
setResponseStatus(e, 401);
|
||||
return;
|
||||
}
|
||||
|
||||
db.delete(characterTable).where(eq(characterTable.id, id)).run();
|
||||
|
||||
setResponseStatus(e, 200);
|
||||
return;
|
||||
});
|
||||
38
server/api/character/[id].get.ts
Normal file
38
server/api/character/[id].get.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { and, eq, sql } from 'drizzle-orm';
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { characterTable } from '~/db/schema';
|
||||
import type { Character } from '~/types/character';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const id = getRouterParam(e, "id");
|
||||
|
||||
if(!id)
|
||||
{
|
||||
setResponseStatus(e, 400);
|
||||
return;
|
||||
}
|
||||
|
||||
const session = await getUserSession(e);
|
||||
|
||||
if(!session.user)
|
||||
{
|
||||
setResponseStatus(e, 401);
|
||||
return;
|
||||
}
|
||||
|
||||
const db = useDatabase();
|
||||
const character = db.select({
|
||||
id: characterTable.id,
|
||||
name: characterTable.name,
|
||||
progress: characterTable.progress,
|
||||
owner: characterTable.owner
|
||||
}).from(characterTable).where(and(eq(characterTable.id, id), eq(characterTable.owner, session.user.id))).get();
|
||||
|
||||
if(character !== undefined)
|
||||
{
|
||||
return character as Character;
|
||||
}
|
||||
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
});
|
||||
45
server/api/character/[id].post.ts
Normal file
45
server/api/character/[id].post.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { eq } from 'drizzle-orm';
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { characterTable } from '~/db/schema';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const id = getRouterParam(e, "id");
|
||||
if(!id)
|
||||
{
|
||||
setResponseStatus(e, 400);
|
||||
return;
|
||||
}
|
||||
|
||||
const body = await readBody(e);
|
||||
if(!body)
|
||||
{
|
||||
setResponseStatus(e, 400);
|
||||
return;
|
||||
}
|
||||
|
||||
const db = useDatabase();
|
||||
const old = db.select({ id: characterTable.id, owner: characterTable.owner }).from(characterTable).where(eq(characterTable.id, parseInt(id))).get();
|
||||
|
||||
if(!old)
|
||||
{
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
}
|
||||
|
||||
const session = await getUserSession(e);
|
||||
if(!session.user || old.owner !== session.user.id || session.user.state !== 1)
|
||||
{
|
||||
setResponseStatus(e, 401);
|
||||
return;
|
||||
}
|
||||
|
||||
db.update(characterTable).set({
|
||||
name: body.name,
|
||||
progress: body.progress,
|
||||
}).where(eq(characterTable.id, parseInt(id))).run();
|
||||
|
||||
await useStorage('cache').removeItem(`nitro:functions:character:${id}.json`);
|
||||
|
||||
setResponseStatus(e, 200);
|
||||
return;
|
||||
});
|
||||
264
server/api/character/[id]/compiled.get.ts
Normal file
264
server/api/character/[id]/compiled.get.ts
Normal file
@@ -0,0 +1,264 @@
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { characterTable } from '~/db/schema';
|
||||
import type { 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 / 3)] as [MainStat, number]).reduce((p, v) => { p[v[0]] = v[1]; return p }, {} as Record<MainStat, number>),
|
||||
level: character.progress.level,
|
||||
features: {
|
||||
action: [],
|
||||
reaction: [],
|
||||
freeaction: [],
|
||||
misc: [],
|
||||
},
|
||||
abilities: {
|
||||
athletics: [0, 0],
|
||||
acrobatics: [0, 0],
|
||||
intimidation: [0, 0],
|
||||
sleightofhand: [0, 0],
|
||||
stealth: [0, 0],
|
||||
survival: [0, 0],
|
||||
investigation: [0, 0],
|
||||
history: [0, 0],
|
||||
religion: [0, 0],
|
||||
arcana: [0, 0],
|
||||
understanding: [0, 0],
|
||||
perception: [0, 0],
|
||||
performance: [0, 0],
|
||||
medecine: [0, 0],
|
||||
persuasion: [0, 0],
|
||||
animalhandling: [0, 0],
|
||||
deception: [0, 0]
|
||||
},
|
||||
spellslots: 0,
|
||||
spellranks: {
|
||||
instinct: 0,
|
||||
knowledge: 0,
|
||||
precision: 0
|
||||
},
|
||||
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],
|
||||
posion: [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: "",
|
||||
};
|
||||
|
||||
features.forEach(e => e[1].forEach((_e, i) => applyTrainingOption(e[0], _e, compiled, i === e[1].length - 1)));
|
||||
specialFeatures(compiled, character.progress.training);
|
||||
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.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.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]++);
|
||||
|
||||
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<MainStat, DoubleIndex<TrainingLevel>[]>)
|
||||
{
|
||||
//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)
|
||||
{
|
||||
|
||||
} */
|
||||
function getFeaturesOf(stat: MainStat, progression: DoubleIndex<TrainingLevel>[]): TrainingOption[]
|
||||
{
|
||||
const config = characterData as CharacterConfig;
|
||||
return progression.map(e => config.training[stat][e[0]][e[1]]);
|
||||
}
|
||||
Reference in New Issue
Block a user