obsidian-visualiser/app/types/character.d.ts

297 lines
9.6 KiB
TypeScript

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<TObj extends object> = {
[TKey in keyof TObj & (string | number)]:
TObj[TKey] extends any[] ? `${TKey}` :
TObj[TKey] extends object
? `${TKey}` | `${TKey}/${RecursiveKeyOf<TObj[TKey]>}`
: `${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<MainStat, Partial<Record<TrainingLevel, number>>>;
leveling: Partial<Record<Level, number>>;
abilities: Partial<Record<Ability, number>>;
variables: CharacterVariables;
choices: Record<FeatureID, number[]>;
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;
};
type CommonState = {
capacity?: number;
powercost?: number;
};
type StateBufferKeys = typeof ITEM_BUFFER_KEYS[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;
buffer?: Partial<Record<StateBufferKeys, PropertySum>>;
};
export type CharacterConfig = {
peoples: Record<string, RaceConfig>;
training: Record<MainStat, Record<TrainingLevel, FeatureID[]>>;
spells: Record<string, SpellConfig>;
aspects: Record<string, AspectConfig>;
features: Record<FeatureID, Feature>;
enchantments: Record<string, EnchantementConfig>;
items: Record<string, ItemConfig>;
action: Record<string, { id: string, name: string, description: string, cost: number }>;
reaction: Record<string, { id: string, name: string, description: string, cost: number }>;
freeaction: Record<string, { id: string, name: string, description: string }>;
passive: Record<string, { id: string, name: string, description: string }>;
texts: Record<i18nID, Localized>;
trees: Record<string, TreeStructure>;
//Each of these groups extend an existing feature as they all use the same properties
sickness: Record<FeatureID, { name: string, stage: number }>; //TODO
poisons: Record<FeatureID, { name: string, difficulty: number, efficienty: number, solubility: number }>; //TODO
dedications: Record<FeatureID, { name: string, requirement: Array<{ stat: MainStat, amount: number }> }>; //TODO
};
export type EnchantementConfig = {
id: string;
name: string; //TODO -> TextID
description: i18nID;
effect: Array<FeatureEquipment | FeatureValue | FeatureList>;
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<FeatureValue | FeatureEquipment | FeatureList>;
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<WeaponType>;
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<SpellElement>;
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<Level, FeatureID[]>;
};
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<CompiledCharacter> | 'spec' | 'ability' | 'training';
value: number | `modifier/${MainStat}` | false;
}
export type FeatureEquipment = {
id: FeatureID;
category: "value";
operation: "add" | "set" | "min";
property: StateBufferKeys;
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<FeatureValue | FeatureList> }>; //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<SpellType | 'arts', 0 | 1 | 2 | 3>;
aspect: {
id: string,
amount: number;
duration: number;
shift_bonus: number;
tier: 0 | 1 | 2;
bonus?: Partial<CompiledCharacter['bonus']>;
};
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<Record<MainStat, number>>; //Defense aux jets de resistance
abilities: Partial<Record<Ability, number>>;
spells: {
type: Partial<Record<SpellType | 'arts', number>>;
rank: Partial<Record<1 | 2 | 3 | 4, number>>;
elements: Partial<Record<SpellElement, number>>;
};
weapon: Partial<Record<WeaponType, number>>;
resistance: Partial<Record<Resistance, number>>; //Bonus à l'attaque
}; //Any special bonus goes here
craft: { level: number, bonus: number };
modifier: Record<MainStat, number>;
abilities: Partial<Record<Ability, number>>;
level: number;
lists: { [K in FeatureList['list']]?: string[] }; //string => ListItem ID
notes: { public: string, private: string };
};