import type { MAIN_STATS, ABILITIES, LEVELS, TRAINING_LEVELS, SPELL_TYPES, CATEGORIES, SPELL_ELEMENTS, ALIGNMENTS, RESISTANCES, DAMAGE_TYPES, WEAPON_TYPES, PropertySum, ITEM_BUFFER_KEYS } from "#shared/character.util"; import type { Localized } from "../types/general"; export type MainStat = typeof MAIN_STATS[number]; export type Ability = typeof ABILITIES[number]; export type Level = typeof LEVELS[number]; export type TrainingLevel = typeof TRAINING_LEVELS[number]; export type SpellType = typeof SPELL_TYPES[number]; export type Category = typeof CATEGORIES[number]; export type SpellElement = typeof SPELL_ELEMENTS[number]; export type Alignment = typeof ALIGNMENTS[number]; export type Resistance = typeof RESISTANCES[number]; export type DamageType = typeof DAMAGE_TYPES[number]; export type WeaponType = typeof WEAPON_TYPES[number]; export type FeatureID = string; export type i18nID = string; export type RecursiveKeyOf = { [TKey in keyof TObj & (string | number)]: TObj[TKey] extends any[] ? `${TKey}` : TObj[TKey] extends object ? `${TKey}` | `${TKey}/${RecursiveKeyOf}` : `${TKey}`; }[keyof TObj & (string | number)]; export type Character = { id: number; name: string; //Free text people?: string; //People ID level: number; aspect?: string; //Aspect ID notes?: { public?: string, private?: string }; //Free text training: Record>>; leveling: Partial>; abilities: Partial>; variables: CharacterVariables; choices: Record; owner: number; username?: string; visibility: "private" | "public"; campaign?: number; }; export type CharacterVariables = { health: number; mana: number; exhaustion: number; sickness: Array<{ id: string, state: number | true }>; poisons: Array<{ id: string, state: number | true }>; spells: string[]; //Spell ID items: ItemState[]; money: number; }; export type TreeStructure = { name: string; nodes: FeatureID[]; // { 'from_id': { 'pathname': 'to_id' } }; paths: Record>; }; type CommonState = { capacity?: number; powercost?: number; }; type ArmorState = { loss: number, health?: number, absorb?: { flat?: number, percent?: number } }; type WeaponState = { attack?: number | string, hit?: number }; type WondrousState = { }; type MundaneState = { }; type ItemState = { id: string; amount: number; enchantments?: string[]; charges?: number; equipped?: boolean; state?: (ArmorState | WeaponState | WondrousState | MundaneState) & CommonState; }; export type CharacterConfig = { peoples: Record; training: Record>; spells: Record; aspects: Record; features: Record; enchantments: Record; items: Record; action: Record; reaction: Record; freeaction: Record; passive: Record; texts: Record; trees: Record; //Each of these groups extend an existing feature as they all use the same properties sickness: Record; //TODO poisons: Record; //TODO dedications: Record }>; //TODO }; export type EnchantementConfig = { id: string; name: string; //TODO -> TextID description: i18nID; effect: Array; power: number; restrictions?: Array<'armor' | 'mundane' | 'wondrous' | 'weapon' | `armor/${ArmorConfig['type']}` | `weapon/${WeaponConfig['type'][number]}`>; // Need to respect *any* of the restriction, not every restrictions. } export type ItemConfig = CommonItemConfig & (ArmorConfig | WeaponConfig | WondrousConfig | MundaneConfig); type CommonItemConfig = { id: string; name: string; //TODO -> TextID flavoring?: i18nID; description: i18nID; rarity: 'common' | 'uncommon' | 'rare' | 'legendary'; weight?: number; //Optionnal but highly recommended price?: number; //Optionnal but highly recommended capacity?: number; //Optionnal as most mundane items should not receive enchantments (potions, herbal heals, etc...) powercost?: number; //Optionnal charge?: number //Max amount of charges enchantments?: string[]; //Enchantment ID effects?: Array; equippable: boolean; consummable: boolean; craft?: { mineral: number, natural: number, processed: number, magical: number }; } type ArmorConfig = { category: 'armor'; health: number; type: 'light' | 'medium' | 'heavy'; absorb: { static: number, percent: number }; }; type WeaponConfig = { category: 'weapon'; type: Array; damage: { value: string; //Dice formula type: DamageType; }; }; type WondrousConfig = { category: 'wondrous'; }; type MundaneConfig = { category: 'mundane'; }; export type SpellConfig = { id: string; name: string; //TODO -> TextID rank: 1 | 2 | 3 | 4; type: SpellType; cost: number; speed: "action" | "reaction" | number; elements: Array; description: string; //TODO -> TextID concentration: boolean; range: 'personnal' | number; tags?: string[]; }; export type ArtConfig = { id: string; name: string; //TODO -> TextID rank: 1 | 2 | 3; type: "arts"; difficulty: number; description: string; //TODO -> TextID tags?: string[]; }; export type RaceConfig = { id: string; name: string; //TODO -> TextID description: string; //TODO -> TextID options: Record; }; export type AspectConfig = { id: string; name: string; description: string; //TODO -> TextID stat: MainStat | 'special'; alignment: Alignment; magic: boolean; difficulty: number; physic: { min: number, max: number }; mental: { min: number, max: number }; personality: { min: number, max: number }; options: FeatureItem[]; }; export type FeatureValue = { id: FeatureID; category: "value"; operation: "add" | "set" | "min"; property: RecursiveKeyOf | 'spec' | 'ability' | 'training'; value: number | `modifier/${MainStat}` | false; } export type FeatureEquipment = { id: FeatureID; category: "value"; operation: "add" | "set" | "min"; property: `item/${RecursiveKeyOf<(ArmorState | WeaponState | WondrousState | MundaneState) & CommonState>}`; value: number | `modifier/${MainStat}` | false; } export type FeatureList = { id: FeatureID; category: "list"; list: "spells" | "sickness" | "action" | "reaction" | "freeaction" | "passive"; action: "add" | "remove"; item: string; }; export type FeatureChoice = { id: FeatureID; category: "choice"; text: string; //TODO -> TextID settings?: { //If undefined, amount is 1 by default amount: number; exclusive: boolean; //Disallow to pick the same option twice }; options: Array<{ text: string, effects: Array }>; //TODO -> TextID }; export type FeatureItem = FeatureValue | FeatureList | FeatureChoice; export type Feature = { id: FeatureID; description: string; //TODO -> TextID effect: FeatureItem[]; }; export type CompiledCharacter = { id: number; owner?: number; username?: string; name: string; health: number; //Max mana: number; //Max race: string; spellslots: number; //Max artslots: number; //Max spellranks: Record; aspect: { id: string, amount: number; duration: number; shift_bonus: number; tier: 0 | 1 | 2; bonus?: Partial; }; speed: number | false; capacity: number | false; initiative: number; exhaust: number; itempower: number; variables: CharacterVariables, defense: { hardcap: number; 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; magicinstinct: number; }; bonus: { defense: Partial>; //Defense aux jets de resistance abilities: Partial>; spells: { type: Partial>; rank: Partial>; elements: Partial>; }; weapon: Partial>; resistance: Partial>; //Bonus à l'attaque }; //Any special bonus goes here craft: { level: number, bonus: number }; modifier: Record; abilities: Partial>; level: number; lists: { [K in FeatureList['list']]?: string[] }; //string => ListItem ID notes: { public: string, private: string }; };