essences/
talent_tree.rs

1use crate::prelude::*;
2
3use crate::currency::{CurrencyId, CurrencyUnit};
4use crate::items::AttributeId;
5use std::collections::BTreeMap;
6
7#[declare]
8pub type TalentId = Uuid;
9
10/// Wrapper around talent level map for Rhai script access.
11#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Tsify)]
12pub struct TalentLevelsMap(pub BTreeMap<TalentId, i64>);
13
14impl TalentLevelsMap {
15    pub fn get(&self, id: &TalentId) -> Option<&i64> {
16        self.0.get(id)
17    }
18
19    pub fn insert(&mut self, id: TalentId, level: i64) {
20        self.0.insert(id, level);
21    }
22
23    pub fn values(&self) -> impl Iterator<Item = &i64> {
24        self.0.values()
25    }
26}
27
28impl CustomType for TalentLevelsMap {
29    fn build(mut builder: TypeBuilder<Self>) {
30        builder.with_name("TalentLevelsMap").with_indexer_get(
31            |map: &mut TalentLevelsMap, idx: Uuid| -> rhai::Dynamic {
32                match map.0.get(&idx) {
33                    Some(&level) => level.into(),
34                    None => ().into(),
35                }
36            },
37        );
38    }
39}
40
41/// Настройки дерева талантов
42#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, Tsify)]
43pub struct TalentTreeSettings {
44    #[schemars(title = "Сколько секунд изучения скипает один таймскип билетик")]
45    pub time_skip_ticket_skips_sec: u64,
46
47    #[schemars(
48        title = "Id валюты для скипа изучения талантов (брюли)",
49        schema_with = "currency_link_id_schema"
50    )]
51    pub skip_currency_id: CurrencyId,
52
53    #[schemars(title = "Сколько секунд изучения скипает одна единица валюты")]
54    pub skip_currency_skips_sec: u64,
55}
56
57/// Шаблон таланта
58#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, Tsify)]
59pub struct TalentTemplate {
60    #[schemars(schema_with = "id_schema")]
61    pub id: TalentId,
62
63    #[schemars(title = "Название")]
64    pub name: i18n::I18nString,
65
66    #[schemars(title = "Описание")]
67    pub description: i18n::I18nString,
68
69    #[schemars(
70        title = "Скрипт, возвращающий значения для подстановки в описание",
71        schema_with = "option_script_schema"
72    )]
73    pub description_values_script: Option<String>,
74
75    #[schemars(title = "URL картинки", schema_with = "webp_url_schema")]
76    pub icon_url: String,
77
78    #[schemars(title = "Иконка", schema_with = "asset_talent_icon_schema")]
79    pub icon_path: String,
80
81    #[schemars(title = "Уровни таланта")]
82    pub levels: Vec<TalentLevel>,
83
84    #[schemars(title = "Условие разблокировки")]
85    pub unlock_condition: TalentUnlockCondition,
86
87    #[schemars(title = "Позиция в дереве (для UI)")]
88    pub position: TalentPosition,
89}
90
91/// Уровень таланта (у каждого таланта 1-5 уровней)
92#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, Tsify)]
93pub struct TalentLevel {
94    #[schemars(title = "Номер уровня (1-based)")]
95    pub level: i64,
96
97    #[schemars(title = "Стоимость изучения этого уровня")]
98    pub cost: CurrencyUnit,
99
100    #[schemars(title = "Время изучения в секундах")]
101    pub duration_sec: u64,
102
103    /// Бонусы, применяемые к атрибутам сущности (HP, урон, защита и т.д.)
104    #[schemars(title = "Бонусы атрибутов")]
105    pub attribute_bonuses: Vec<TalentAttributeBonus>,
106
107    /// Модификаторы, обрабатываемые бэкендом напрямую (не через атрибуты и не через скрипты)
108    #[schemars(title = "Бэкенд-модификаторы")]
109    pub backend_modifiers: Vec<TalentBackendModifier>,
110}
111
112/// Бонус атрибута сущности от таланта (плоское значение)
113#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, Tsify)]
114pub struct TalentAttributeBonus {
115    #[schemars(title = "Id атрибута", schema_with = "attribute_link_id_schema")]
116    pub attribute_id: AttributeId,
117
118    #[schemars(title = "Значение (плоское)")]
119    pub value: i64,
120}
121
122/// Модификаторы, которые бэкенд применяет явно в своей логике.
123/// Каждый вариант соответствует конкретному месту в бэкенд-коде.
124#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, Tsify)]
125pub enum TalentBackendModifier {
126    #[schemars(title = "Ускорение исследования талантов (%)")]
127    TalentResearchSpeedPercent(f64),
128}
129
130/// Условие разблокировки таланта
131#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, Tsify)]
132pub struct TalentUnlockCondition {
133    /// Список талантов, которые должны быть полностью изучены (пустой = нет требований)
134    #[schemars(
135        title = "Id требуемых талантов",
136        schema_with = "talent_link_id_array_schema"
137    )]
138    pub required_talents: Vec<TalentId>,
139
140    /// Минимальное суммарное количество вложенных очков талантов (0 = нет требований)
141    #[schemars(title = "Необходимое количество вложенных очков талантов")]
142    pub required_points: i64,
143}
144
145/// Позиция таланта в дереве (для отрисовки на клиенте)
146#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, Tsify)]
147pub struct TalentPosition {
148    #[schemars(title = "Колонка")]
149    pub col: i64,
150
151    #[schemars(title = "Строка")]
152    pub row: i64,
153}