import { z, type ZodRawShape } from "zod"; import { characterTable } from "~/db/schema"; export const MAIN_STATS = ["strength","dexterity","constitution","intelligence","curiosity","charisma","psyche"] as const; export type MainStat = typeof MAIN_STATS[number]; export const ABILITIES = ["athletics","acrobatics","intimidation","sleightofhand","stealth","survival","investigation","history","religion","arcana","understanding","perception","performance","medecine","persuasion","animalhandling","deception"] as const; export type Ability = typeof ABILITIES[number]; export const LEVELS = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20] as const; export type Level = typeof LEVELS[number]; export const TRAINING_LEVELS = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] as const; export type TrainingLevel = typeof TRAINING_LEVELS[number]; export const SPELL_TYPES = ["precision","knowledge","instinct","arts"] as const; export type SpellType = typeof SPELL_TYPES[number]; export const CATEGORIES = ["action","reaction","freeaction","misc"] as const; export type Category = typeof CATEGORIES[number]; export const SPELL_ELEMENTS = ["fire","ice","thunder","earth","arcana","air","nature","light","psyche"] as const; export type SpellElement = typeof SPELL_ELEMENTS[number]; export const RESISTANCES = ["stun","bleed","poison","fear","influence","charm","possesion","precision","knowledge","instinct"] as const; export type Resistance = typeof RESISTANCES[number]; export type DoubleIndex = [T, number]; export const defaultCharacter: Character = { id: -1, name: "", people: undefined, level: 1, health: 0, mana: 0, training: MAIN_STATS.reduce((p, v) => { p[v] = [[0, 0]]; return p; }, {} as Record[]>), leveling: [[1, 0]], abilities: {}, spells: [], modifiers: {}, owner: -1, visibility: "private", }; export const mainStatTexts: Record = { "strength": "Force", "dexterity": "Dextérité", "constitution": "Constitution", "intelligence": "Intelligence", "curiosity": "Curiosité", "charisma": "Charisme", "psyche": "Psyché", } export const elementTexts: Record = { fire: { class: 'text-light-red dark:text-dark-red', text: 'Feu' }, ice: { class: 'text-light-blue dark:text-dark-blue', text: 'Glace' }, thunder: { class: 'text-light-yellow dark:text-dark-yellow', text: 'Foudre' }, earth: { class: 'text-light-orange dark:text-dark-orange', text: 'Terre' }, arcana: { class: 'text-light-purple dark:text-dark-purple', text: 'Arcane' }, air: { class: 'text-light-green dark:text-dark-green', text: 'Air' }, nature: { class: 'text-light-green dark:text-dark-green', text: 'Nature' }, light: { class: 'text-light-yellow dark:text-dark-yellow', text: 'Lumière' }, psyche: { class: 'text-light-purple dark:text-dark-purple', text: 'Psy' }, } export const spellTypeTexts: Record = { "instinct": "Instinct", "knowledge": "Savoir", "precision": "Précision", "arts": "Oeuvres" }; export const CharacterValidation = z.object({ id: z.number(), name: z.string(), people: z.number().nullable(), level: z.number().min(1).max(20), aspect: z.number().nullable().optional(), notes: z.string().nullable().optional(), health: z.number().default(0), mana: z.number().default(0), training: z.object(MAIN_STATS.reduce((p, v) => { p[v] = z.array(z.tuple([z.number().min(0).max(15), z.number()])); return p; }, {} as Record>>)), leveling: z.array(z.tuple([z.number().min(1).max(20), z.number()])), abilities: z.object(ABILITIES.reduce((p, v) => { p[v] = z.tuple([z.number(), z.number()]); return p; }, {} as Record>)).partial(), spells: z.string().array(), modifiers: z.object(MAIN_STATS.reduce((p, v) => { p[v] = z.number(); return p; }, {} as Record)).partial(), owner: z.number(), username: z.string().optional(), visibility: z.enum(["public", "private"]), thumbnail: z.any(), }) export type Character = { id: number; name: string; people?: number; level: number; aspect?: number | null; notes?: string | null; health: number; mana: number; training: Record[]>; leveling: DoubleIndex[]; abilities: Partial>; //First is the ability, second is the max increment spells: string[]; //Spell ID modifiers: Partial>; owner: number; username?: string; visibility: "private" | "public"; }; export type CharacterValues = { health: number; mana: number; }; export type CharacterConfig = { peoples: Race[], training: Record>; abilities: Record; resistances: Record; spells: SpellConfig[]; }; export type SpellConfig = { id: string; name: string; rank: 1 | 2 | 3; type: SpellType; cost: number; speed: "action" | "reaction" | number; elements: Array; effect: string; tags?: string[]; }; export type AbilityConfig = { max: [MainStat, MainStat]; name: string; description: string; }; export type ResistanceConfig = { name: string; statistic: MainStat; }; export type Race = { name: string; description: string; utils: { maxOption: number; }; options: Record; }; export type RaceOption = { training?: number; health?: number; mana?: number; shaping?: number; modifier?: number; abilities?: number; spellslots?: number; }; export type Feature = { text?: string; } & (ActionFeature | ReactionFeature | FreeActionFeature | BonusFeature | MiscFeature); type ActionFeature = { type: "action"; cost: 1 | 2 | 3; text: string; }; type ReactionFeature = { type: "reaction"; text: string; }; type FreeActionFeature = { type: "freeaction"; text: string; }; type BonusFeature = { type: "bonus"; action: "add" | "remove" | "set" | "cap"; value: number; property: string; }; type MiscFeature = { type: "misc"; text: string; }; export type TrainingOption = { description: Array<{ text: string; disposable?: boolean; replaced?: boolean; category?: Category; }>; //Automatically calculated by compiler mana?: number; health?: number; speed?: false | number; initiative?: number; mastery?: keyof CompiledCharacter["mastery"]; spellrank?: SpellType; defense?: Array; resistance?: [Resistance, "attack" | "defense"][]; spell?: string; //Used during character creation, not used by compiler modifier?: number; ability?: number; spec?: number; spellslot?: number | MainStat; arts?: number | MainStat; features?: Feature[]; //TODO }; export type CompiledCharacter = { id: number; owner?: number; username?: string; name: string; health: number; mana: number; race: number; spellslots: number; artslots: number; spellranks: Record; aspect: string; speed: number | false; initiative: number; spells: string[]; values: CharacterValues, defense: { static: number; activeparry: number; activedodge: number; passiveparry: number; passivedodge: number; }; mastery: { strength: number; dexterity: number; shield: number; armor: number; multiattack: number; magicpower: number; magicspeed: number; magicelement: number; }; //First is attack, second is defense resistance: Record; modifier: Record; abilities: Partial>; level: number; features: Record; //Currently: List of training option as text. TODO: Update to a more complex structure later notes: string; };